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  }