github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/go/types/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 types 8 9 import "sync" 10 11 // A MethodSetCache records the method set of each type T for which 12 // MethodSet(T) is called so that repeat queries are fast. 13 // The zero value is a ready-to-use cache instance. 14 type MethodSetCache struct { 15 mu sync.Mutex 16 named map[*Named]struct{ value, pointer *MethodSet } // method sets for named N and *N 17 others map[Type]*MethodSet // all other types 18 } 19 20 // MethodSet returns the method set of type T. It is thread-safe. 21 // 22 // If cache is nil, this function is equivalent to NewMethodSet(T). 23 // Utility functions can thus expose an optional *MethodSetCache 24 // parameter to clients that care about performance. 25 // 26 func (cache *MethodSetCache) MethodSet(T Type) *MethodSet { 27 if cache == nil { 28 return NewMethodSet(T) 29 } 30 cache.mu.Lock() 31 defer cache.mu.Unlock() 32 33 switch T := T.(type) { 34 case *Named: 35 return cache.lookupNamed(T).value 36 37 case *Pointer: 38 if N, ok := T.Elem().(*Named); ok { 39 return cache.lookupNamed(N).pointer 40 } 41 } 42 43 // all other types 44 // (The map uses pointer equivalence, not type identity.) 45 mset := cache.others[T] 46 if mset == nil { 47 mset = NewMethodSet(T) 48 if cache.others == nil { 49 cache.others = make(map[Type]*MethodSet) 50 } 51 cache.others[T] = mset 52 } 53 return mset 54 } 55 56 func (cache *MethodSetCache) lookupNamed(named *Named) struct{ value, pointer *MethodSet } { 57 if cache.named == nil { 58 cache.named = make(map[*Named]struct{ value, pointer *MethodSet }) 59 } 60 // Avoid recomputing mset(*T) for each distinct Pointer 61 // instance whose underlying type is a named type. 62 msets, ok := cache.named[named] 63 if !ok { 64 msets.value = NewMethodSet(named) 65 msets.pointer = NewMethodSet(NewPointer(named)) 66 cache.named[named] = msets 67 } 68 return msets 69 }