github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/types/typeutil/methodsetcache.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file implements a cache of method sets. 6 7 package typeutil 8 9 import ( 10 "go/types" 11 "sync" 12 ) 13 14 // A MethodSetCache records the method set of each type T for which 15 // MethodSet(T) is called so that repeat queries are fast. 16 // The zero value is a ready-to-use cache instance. 17 type MethodSetCache struct { 18 mu sync.Mutex 19 named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N 20 others map[types.Type]*types.MethodSet // all other types 21 } 22 23 // MethodSet returns the method set of type T. It is thread-safe. 24 // 25 // If cache is nil, this function is equivalent to types.NewMethodSet(T). 26 // Utility functions can thus expose an optional *MethodSetCache 27 // parameter to clients that care about performance. 28 func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { 29 if cache == nil { 30 return types.NewMethodSet(T) 31 } 32 cache.mu.Lock() 33 defer cache.mu.Unlock() 34 35 switch T := T.(type) { 36 case *types.Named: 37 return cache.lookupNamed(T).value 38 39 case *types.Pointer: 40 if N, ok := T.Elem().(*types.Named); ok { 41 return cache.lookupNamed(N).pointer 42 } 43 } 44 45 // all other types 46 // (The map uses pointer equivalence, not type identity.) 47 mset := cache.others[T] 48 if mset == nil { 49 mset = types.NewMethodSet(T) 50 if cache.others == nil { 51 cache.others = make(map[types.Type]*types.MethodSet) 52 } 53 cache.others[T] = mset 54 } 55 return mset 56 } 57 58 func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { 59 if cache.named == nil { 60 cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) 61 } 62 // Avoid recomputing mset(*T) for each distinct Pointer 63 // instance whose underlying type is a named type. 64 msets, ok := cache.named[named] 65 if !ok { 66 msets.value = types.NewMethodSet(named) 67 msets.pointer = types.NewMethodSet(types.NewPointer(named)) 68 cache.named[named] = msets 69 } 70 return msets 71 }