// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package typeutil defines various utilities for types, such as Map, // a mapping from types.Type to interface{} values. package typeutil // import "golang.org/x/tools/go/types/typeutil" import ( "bytes" "fmt" "go/types" "reflect" ) // Map is a hash-table-based mapping from types (types.Type) to // arbitrary interface{} values. The concrete types that implement // the Type interface are pointers. Since they are not canonicalized, // == cannot be used to check for equivalence, and thus we cannot // simply use a Go map. // // Just as with map[K]V, a nil *Map is a valid empty map. // // Not thread-safe. // type Map struct { hasher Hasher // shared by many Maps table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused length int // number of map entries } // entry is an entry (key/value association) in a hash bucket. type entry struct { key types.Type value interface{} } // SetHasher sets the hasher used by Map. // // All Hashers are functionally equivalent but contain internal state // used to cache the results of hashing previously seen types. // // A single Hasher created by MakeHasher() may be shared among many // Maps. This is recommended if the instances have many keys in // common, as it will amortize the cost of hash computation. // // A Hasher may grow without bound as new types are seen. Even when a // type is deleted from the map, the Hasher never shrinks, since other // types in the map may reference the deleted type indirectly. // // Hashers are not thread-safe, and read-only operations such as // Map.Lookup require updates to the hasher, so a full Mutex lock (not a // read-lock) is require around all Map operations if a shared // hasher is accessed from multiple threads. // // If SetHasher is not called, the Map will create a private hasher at // the first call to Insert. // func (m *Map) SetHasher(hasher Hasher) { m.hasher = hasher } // Delete removes the entry with the given key, if any. // It returns true if the entry was found. // func (m *Map) Delete(key types.Type) bool { if m != nil && m.table != nil { hash := m.hasher.Hash(key) bucket := m.table[hash] for i, e := range bucket { if e.key != nil && types.Identical(key, e.key) { // We can't compact the bucket as it // would disturb iterators. bucket[i] = entry{} m.length-- return true } } } return false } // At returns the map entry for the given key. // The result is nil if the entry is not present. // func (m *Map) At(key types.Type) interface{} { if m != nil && m.table != nil { for _, e := range m.table[m.hasher.Hash(key)] { if e.key != nil && types.Identical(key, e.key) { return e.value } } } return nil } // Set sets the map entry for key to val, // and returns the previous entry, if any. func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) { if m.table != nil { hash := m.hasher.Hash(key) bucket := m.table[hash] var hole *entry for i, e := range bucket { if e.key == nil { hole = &bucket[i] } else if types.Identical(key, e.key) { prev = e.value bucket[i].value = value return } } if hole != nil { *hole = entry{key, value} // overwrite deleted entry } else { m.table[hash] = append(bucket, entry{key, value}) } } else { if m.hasher.memo == nil { m.hasher = MakeHasher() } hash := m.hasher.Hash(key) m.table = map[uint32][]entry{hash: {entry{key, value}}} } m.length++ return } // Len returns the number of map entries. func (m *Map) Len() int { if m != nil { return m.length } return 0 } // Iterate calls function f on each entry in the map in unspecified order. // // If f should mutate the map, Iterate provides the same guarantees as // Go maps: if f deletes a map entry that Iterate has not yet reached, // f will not be invoked for it, but if f inserts a map entry that // Iterate has not yet reached, whether or not f will be invoked for // it is unspecified. // func (m *Map) Iterate(f func(key types.Type, value interface{})) { if m != nil { for _, bucket := range m.table { for _, e := range bucket { if e.key != nil { f(e.key, e.value) } } } } } // Keys returns a new slice containing the set of map keys. // The order is unspecified. func (m *Map) Keys() []types.Type { keys := make([]types.Type, 0, m.Len()) m.Iterate(func(key types.Type, _ interface{}) { keys = append(keys, key) }) return keys } func (m *Map) toString(values bool) string { if m == nil { return "{}" } var buf bytes.Buffer fmt.Fprint(&buf, "{") sep := "" m.Iterate(func(key types.Type, value interface{}) { fmt.Fprint(&buf, sep) sep = ", " fmt.Fprint(&buf, key) if values { fmt.Fprintf(&buf, ": %q", value) } }) fmt.Fprint(&buf, "}") return buf.String() } // String returns a string representation of the map's entries. // Values are printed using fmt.Sprintf("%v", v). // Order is unspecified. // func (m *Map) String() string { return m.toString(true) } // KeysString returns a string representation of the map's key set. // Order is unspecified. // func (m *Map) KeysString() string { return m.toString(false) } //////////////////////////////////////////////////////////////////////// // Hasher // A Hasher maps each type to its hash value. // For efficiency, a hasher uses memoization; thus its memory // footprint grows monotonically over time. // Hashers are not thread-safe. // Hashers have reference semantics. // Call MakeHasher to create a Hasher. type Hasher struct { memo map[types.Type]uint32 } // MakeHasher returns a new Hasher instance. func MakeHasher() Hasher { return Hasher{make(map[types.Type]uint32)} } // Hash computes a hash value for the given type t such that // Identical(t, t') => Hash(t) == Hash(t'). func (h Hasher) Hash(t types.Type) uint32 { hash, ok := h.memo[t] if !ok { hash = h.hashFor(t) h.memo[t] = hash } return hash } // hashString computes the Fowler–Noll–Vo hash of s. func hashString(s string) uint32 { var h uint32 for i := 0; i < len(s); i++ { h ^= uint32(s[i]) h *= 16777619 } return h } // hashFor computes the hash of t. func (h Hasher) hashFor(t types.Type) uint32 { // See Identical for rationale. switch t := t.(type) { case *types.Basic: return uint32(t.Kind()) case *types.Array: return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) case *types.Slice: return 9049 + 2*h.Hash(t.Elem()) case *types.Struct: var hash uint32 = 9059 for i, n := 0, t.NumFields(); i < n; i++ { f := t.Field(i) if f.Anonymous() { hash += 8861 } hash += hashString(t.Tag(i)) hash += hashString(f.Name()) // (ignore f.Pkg) hash += h.Hash(f.Type()) } return hash case *types.Pointer: return 9067 + 2*h.Hash(t.Elem()) case *types.Signature: var hash uint32 = 9091 if t.Variadic() { hash *= 8863 } return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) case *types.Interface: var hash uint32 = 9103 for i, n := 0, t.NumMethods(); i < n; i++ { // See go/types.identicalMethods for rationale. // Method order is not significant. // Ignore m.Pkg(). m := t.Method(i) hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) } return hash case *types.Map: return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) case *types.Chan: return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) case *types.Named: // Not safe with a copying GC; objects may move. return uint32(reflect.ValueOf(t.Obj()).Pointer()) case *types.Tuple: return h.hashTuple(t) } panic(t) } func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { // See go/types.identicalTypes for rationale. n := tuple.Len() var hash uint32 = 9137 + 2*uint32(n) for i := 0; i < n; i++ { hash += 3 * h.Hash(tuple.At(i).Type()) } return hash }