github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/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 // 29 func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { 30 if cache == nil { 31 return types.NewMethodSet(T) 32 } 33 cache.mu.Lock() 34 defer cache.mu.Unlock() 35 36 switch T := T.(type) { 37 case *types.Named: 38 return cache.lookupNamed(T).value 39 40 case *types.Pointer: 41 if N, ok := T.Elem().(*types.Named); ok { 42 return cache.lookupNamed(N).pointer 43 } 44 } 45 46 // all other types 47 // (The map uses pointer equivalence, not type identity.) 48 mset := cache.others[T] 49 if mset == nil { 50 mset = types.NewMethodSet(T) 51 if cache.others == nil { 52 cache.others = make(map[types.Type]*types.MethodSet) 53 } 54 cache.others[T] = mset 55 } 56 return mset 57 } 58 59 func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { 60 if cache.named == nil { 61 cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) 62 } 63 // Avoid recomputing mset(*T) for each distinct Pointer 64 // instance whose underlying type is a named type. 65 msets, ok := cache.named[named] 66 if !ok { 67 msets.value = types.NewMethodSet(named) 68 msets.pointer = types.NewMethodSet(types.NewPointer(named)) 69 cache.named[named] = msets 70 } 71 return msets 72 }