github.com/goplus/llgo@v0.8.3/internal/typeutil/map.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  // Package typeutil defines various utilities for types, such as Map,
     6  // a mapping from types.Type to interface{} values.
     7  package typeutil
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/types"
    13  	"reflect"
    14  
    15  	"github.com/goplus/llgo/internal/aliases"
    16  	"github.com/goplus/llgo/internal/typeparams"
    17  )
    18  
    19  // Map is a hash-table-based mapping from types (types.Type) to
    20  // arbitrary interface{} values.  The concrete types that implement
    21  // the Type interface are pointers.  Since they are not canonicalized,
    22  // == cannot be used to check for equivalence, and thus we cannot
    23  // simply use a Go map.
    24  //
    25  // Just as with map[K]V, a nil *Map is a valid empty map.
    26  //
    27  // Not thread-safe.
    28  type Map struct {
    29  	hasher Hasher             // shared by many Maps
    30  	table  map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
    31  	length int                // number of map entries
    32  }
    33  
    34  // entry is an entry (key/value association) in a hash bucket.
    35  type entry struct {
    36  	key   types.Type
    37  	value interface{}
    38  }
    39  
    40  // SetHasher sets the hasher used by Map.
    41  //
    42  // All Hashers are functionally equivalent but contain internal state
    43  // used to cache the results of hashing previously seen types.
    44  //
    45  // A single Hasher created by MakeHasher() may be shared among many
    46  // Maps.  This is recommended if the instances have many keys in
    47  // common, as it will amortize the cost of hash computation.
    48  //
    49  // A Hasher may grow without bound as new types are seen.  Even when a
    50  // type is deleted from the map, the Hasher never shrinks, since other
    51  // types in the map may reference the deleted type indirectly.
    52  //
    53  // Hashers are not thread-safe, and read-only operations such as
    54  // Map.Lookup require updates to the hasher, so a full Mutex lock (not a
    55  // read-lock) is require around all Map operations if a shared
    56  // hasher is accessed from multiple threads.
    57  //
    58  // If SetHasher is not called, the Map will create a private hasher at
    59  // the first call to Insert.
    60  func (m *Map) SetHasher(hasher Hasher) {
    61  	m.hasher = hasher
    62  }
    63  
    64  // Delete removes the entry with the given key, if any.
    65  // It returns true if the entry was found.
    66  func (m *Map) Delete(key types.Type) bool {
    67  	if m != nil && m.table != nil {
    68  		hash := m.hasher.Hash(key)
    69  		bucket := m.table[hash]
    70  		for i, e := range bucket {
    71  			if e.key != nil && types.Identical(key, e.key) {
    72  				// We can't compact the bucket as it
    73  				// would disturb iterators.
    74  				bucket[i] = entry{}
    75  				m.length--
    76  				return true
    77  			}
    78  		}
    79  	}
    80  	return false
    81  }
    82  
    83  // At returns the map entry for the given key.
    84  // The result is nil if the entry is not present.
    85  func (m *Map) At(key types.Type) interface{} {
    86  	if m != nil && m.table != nil {
    87  		for _, e := range m.table[m.hasher.Hash(key)] {
    88  			if e.key != nil && types.Identical(key, e.key) {
    89  				return e.value
    90  			}
    91  		}
    92  	}
    93  	return nil
    94  }
    95  
    96  // Set sets the map entry for key to val,
    97  // and returns the previous entry, if any.
    98  func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) {
    99  	if m.table != nil {
   100  		hash := m.hasher.Hash(key)
   101  		bucket := m.table[hash]
   102  		var hole *entry
   103  		for i, e := range bucket {
   104  			if e.key == nil {
   105  				hole = &bucket[i]
   106  			} else if types.Identical(key, e.key) {
   107  				prev = e.value
   108  				bucket[i].value = value
   109  				return
   110  			}
   111  		}
   112  
   113  		if hole != nil {
   114  			*hole = entry{key, value} // overwrite deleted entry
   115  		} else {
   116  			m.table[hash] = append(bucket, entry{key, value})
   117  		}
   118  	} else {
   119  		if m.hasher.memo == nil {
   120  			m.hasher = MakeHasher()
   121  		}
   122  		hash := m.hasher.Hash(key)
   123  		m.table = map[uint32][]entry{hash: {entry{key, value}}}
   124  	}
   125  
   126  	m.length++
   127  	return
   128  }
   129  
   130  // Len returns the number of map entries.
   131  func (m *Map) Len() int {
   132  	if m != nil {
   133  		return m.length
   134  	}
   135  	return 0
   136  }
   137  
   138  // Iterate calls function f on each entry in the map in unspecified order.
   139  //
   140  // If f should mutate the map, Iterate provides the same guarantees as
   141  // Go maps: if f deletes a map entry that Iterate has not yet reached,
   142  // f will not be invoked for it, but if f inserts a map entry that
   143  // Iterate has not yet reached, whether or not f will be invoked for
   144  // it is unspecified.
   145  func (m *Map) Iterate(f func(key types.Type, value interface{})) {
   146  	if m != nil {
   147  		for _, bucket := range m.table {
   148  			for _, e := range bucket {
   149  				if e.key != nil {
   150  					f(e.key, e.value)
   151  				}
   152  			}
   153  		}
   154  	}
   155  }
   156  
   157  // Keys returns a new slice containing the set of map keys.
   158  // The order is unspecified.
   159  func (m *Map) Keys() []types.Type {
   160  	keys := make([]types.Type, 0, m.Len())
   161  	m.Iterate(func(key types.Type, _ interface{}) {
   162  		keys = append(keys, key)
   163  	})
   164  	return keys
   165  }
   166  
   167  func (m *Map) toString(values bool) string {
   168  	if m == nil {
   169  		return "{}"
   170  	}
   171  	var buf bytes.Buffer
   172  	fmt.Fprint(&buf, "{")
   173  	sep := ""
   174  	m.Iterate(func(key types.Type, value interface{}) {
   175  		fmt.Fprint(&buf, sep)
   176  		sep = ", "
   177  		fmt.Fprint(&buf, key)
   178  		if values {
   179  			fmt.Fprintf(&buf, ": %q", value)
   180  		}
   181  	})
   182  	fmt.Fprint(&buf, "}")
   183  	return buf.String()
   184  }
   185  
   186  // String returns a string representation of the map's entries.
   187  // Values are printed using fmt.Sprintf("%v", v).
   188  // Order is unspecified.
   189  func (m *Map) String() string {
   190  	return m.toString(true)
   191  }
   192  
   193  // KeysString returns a string representation of the map's key set.
   194  // Order is unspecified.
   195  func (m *Map) KeysString() string {
   196  	return m.toString(false)
   197  }
   198  
   199  ////////////////////////////////////////////////////////////////////////
   200  // Hasher
   201  
   202  // A Hasher maps each type to its hash value.
   203  // For efficiency, a hasher uses memoization; thus its memory
   204  // footprint grows monotonically over time.
   205  // Hashers are not thread-safe.
   206  // Hashers have reference semantics.
   207  // Call MakeHasher to create a Hasher.
   208  type Hasher struct {
   209  	memo map[types.Type]uint32
   210  
   211  	// ptrMap records pointer identity.
   212  	ptrMap map[interface{}]uint32
   213  
   214  	// sigTParams holds type parameters from the signature being hashed.
   215  	// Signatures are considered identical modulo renaming of type parameters, so
   216  	// within the scope of a signature type the identity of the signature's type
   217  	// parameters is just their index.
   218  	//
   219  	// Since the language does not currently support referring to uninstantiated
   220  	// generic types or functions, and instantiated signatures do not have type
   221  	// parameter lists, we should never encounter a second non-empty type
   222  	// parameter list when hashing a generic signature.
   223  	sigTParams *types.TypeParamList
   224  }
   225  
   226  // MakeHasher returns a new Hasher instance.
   227  func MakeHasher() Hasher {
   228  	return Hasher{
   229  		memo:       make(map[types.Type]uint32),
   230  		ptrMap:     make(map[interface{}]uint32),
   231  		sigTParams: nil,
   232  	}
   233  }
   234  
   235  // Hash computes a hash value for the given type t such that
   236  // Identical(t, t') => Hash(t) == Hash(t').
   237  func (h Hasher) Hash(t types.Type) uint32 {
   238  	hash, ok := h.memo[t]
   239  	if !ok {
   240  		hash = h.hashFor(t)
   241  		h.memo[t] = hash
   242  	}
   243  	return hash
   244  }
   245  
   246  // hashString computes the Fowler–Noll–Vo hash of s.
   247  func hashString(s string) uint32 {
   248  	var h uint32
   249  	for i := 0; i < len(s); i++ {
   250  		h ^= uint32(s[i])
   251  		h *= 16777619
   252  	}
   253  	return h
   254  }
   255  
   256  func HashSig(h Hasher, t *types.Signature) uint32 {
   257  	var hash uint32 = 9091
   258  	if t.Variadic() {
   259  		hash *= 8863
   260  	}
   261  
   262  	// Use a separate hasher for types inside of the signature, where type
   263  	// parameter identity is modified to be (index, constraint). We must use a
   264  	// new memo for this hasher as type identity may be affected by this
   265  	// masking. For example, in func[T any](*T), the identity of *T depends on
   266  	// whether we are mapping the argument in isolation, or recursively as part
   267  	// of hashing the signature.
   268  	//
   269  	// We should never encounter a generic signature while hashing another
   270  	// generic signature, but defensively set sigTParams only if h.mask is
   271  	// unset.
   272  	tparams := t.TypeParams()
   273  	if h.sigTParams == nil && tparams.Len() != 0 {
   274  		h = Hasher{
   275  			// There may be something more efficient than discarding the existing
   276  			// memo, but it would require detecting whether types are 'tainted' by
   277  			// references to type parameters.
   278  			memo: make(map[types.Type]uint32),
   279  			// Re-using ptrMap ensures that pointer identity is preserved in this
   280  			// hasher.
   281  			ptrMap:     h.ptrMap,
   282  			sigTParams: tparams,
   283  		}
   284  	}
   285  
   286  	for i := 0; i < tparams.Len(); i++ {
   287  		tparam := tparams.At(i)
   288  		hash += 7 * h.Hash(tparam.Constraint())
   289  	}
   290  
   291  	return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
   292  }
   293  
   294  // hashFor computes the hash of t.
   295  func (h Hasher) hashFor(t types.Type) uint32 {
   296  	// See Identical for rationale.
   297  	switch t := t.(type) {
   298  	case *types.Basic:
   299  		return uint32(t.Kind())
   300  
   301  	case *aliases.Alias:
   302  		return h.Hash(t.Underlying())
   303  
   304  	case *types.Array:
   305  		return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
   306  
   307  	case *types.Slice:
   308  		return 9049 + 2*h.Hash(t.Elem())
   309  
   310  	case *types.Struct:
   311  		var hash uint32 = 9059
   312  		for i, n := 0, t.NumFields(); i < n; i++ {
   313  			f := t.Field(i)
   314  			if f.Anonymous() {
   315  				hash += 8861
   316  			}
   317  			hash += hashString(t.Tag(i))
   318  			hash += hashString(f.Name()) // (ignore f.Pkg)
   319  			hash += h.Hash(f.Type())
   320  		}
   321  		return hash
   322  
   323  	case *types.Pointer:
   324  		return 9067 + 2*h.Hash(t.Elem())
   325  
   326  	case *types.Signature:
   327  		return HashSig(h, t)
   328  
   329  	case *types.Union:
   330  		return h.hashUnion(t)
   331  
   332  	case *types.Interface:
   333  		// Interfaces are identical if they have the same set of methods, with
   334  		// identical names and types, and they have the same set of type
   335  		// restrictions. See go/types.identical for more details.
   336  		var hash uint32 = 9103
   337  
   338  		// Hash methods.
   339  		for i, n := 0, t.NumMethods(); i < n; i++ {
   340  			// Method order is not significant.
   341  			// Ignore m.Pkg().
   342  			m := t.Method(i)
   343  			// Use shallow hash on method signature to
   344  			// avoid anonymous interface cycles.
   345  			hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type())
   346  		}
   347  
   348  		// Hash type restrictions.
   349  		terms, err := typeparams.InterfaceTermSet(t)
   350  		// if err != nil t has invalid type restrictions.
   351  		if err == nil {
   352  			hash += h.hashTermSet(terms)
   353  		}
   354  
   355  		return hash
   356  
   357  	case *types.Map:
   358  		return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())
   359  
   360  	case *types.Chan:
   361  		return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())
   362  
   363  	case *types.Named:
   364  		hash := h.hashPtr(t.Obj())
   365  		targs := t.TypeArgs()
   366  		for i := 0; i < targs.Len(); i++ {
   367  			targ := targs.At(i)
   368  			hash += 2 * h.Hash(targ)
   369  		}
   370  		return hash
   371  
   372  	case *types.TypeParam:
   373  		return h.hashTypeParam(t)
   374  
   375  	case *types.Tuple:
   376  		return h.hashTuple(t)
   377  
   378  	case interface{ Hash(h Hasher) uint32 }:
   379  		return t.Hash(h)
   380  	}
   381  
   382  	panic(fmt.Sprintf("%T: %v", t, t))
   383  }
   384  
   385  func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
   386  	// See go/types.identicalTypes for rationale.
   387  	n := tuple.Len()
   388  	hash := 9137 + 2*uint32(n)
   389  	for i := 0; i < n; i++ {
   390  		hash += 3 * h.Hash(tuple.At(i).Type())
   391  	}
   392  	return hash
   393  }
   394  
   395  func (h Hasher) hashUnion(t *types.Union) uint32 {
   396  	// Hash type restrictions.
   397  	terms, err := typeparams.UnionTermSet(t)
   398  	// if err != nil t has invalid type restrictions. Fall back on a non-zero
   399  	// hash.
   400  	if err != nil {
   401  		return 9151
   402  	}
   403  	return h.hashTermSet(terms)
   404  }
   405  
   406  func (h Hasher) hashTermSet(terms []*types.Term) uint32 {
   407  	hash := 9157 + 2*uint32(len(terms))
   408  	for _, term := range terms {
   409  		// term order is not significant.
   410  		termHash := h.Hash(term.Type())
   411  		if term.Tilde() {
   412  			termHash *= 9161
   413  		}
   414  		hash += 3 * termHash
   415  	}
   416  	return hash
   417  }
   418  
   419  // hashTypeParam returns a hash of the type parameter t, with a hash value
   420  // depending on whether t is contained in h.sigTParams.
   421  //
   422  // If h.sigTParams is set and contains t, then we are in the process of hashing
   423  // a signature, and the hash value of t must depend only on t's index and
   424  // constraint: signatures are considered identical modulo type parameter
   425  // renaming. To avoid infinite recursion, we only hash the type parameter
   426  // index, and rely on types.Identical to handle signatures where constraints
   427  // are not identical.
   428  //
   429  // Otherwise the hash of t depends only on t's pointer identity.
   430  func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 {
   431  	if h.sigTParams != nil {
   432  		i := t.Index()
   433  		if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
   434  			return 9173 + 3*uint32(i)
   435  		}
   436  	}
   437  	return h.hashPtr(t.Obj())
   438  }
   439  
   440  // hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that
   441  // pointers values are not dependent on the GC.
   442  func (h Hasher) hashPtr(ptr interface{}) uint32 {
   443  	if hash, ok := h.ptrMap[ptr]; ok {
   444  		return hash
   445  	}
   446  	hash := uint32(reflect.ValueOf(ptr).Pointer())
   447  	h.ptrMap[ptr] = hash
   448  	return hash
   449  }
   450  
   451  // shallowHash computes a hash of t without looking at any of its
   452  // element Types, to avoid potential anonymous cycles in the types of
   453  // interface methods.
   454  //
   455  // When an unnamed non-empty interface type appears anywhere among the
   456  // arguments or results of an interface method, there is a potential
   457  // for endless recursion. Consider:
   458  //
   459  //	type X interface { m() []*interface { X } }
   460  //
   461  // The problem is that the Methods of the interface in m's result type
   462  // include m itself; there is no mention of the named type X that
   463  // might help us break the cycle.
   464  // (See comment in go/types.identical, case *Interface, for more.)
   465  func (h Hasher) shallowHash(t types.Type) uint32 {
   466  	// t is the type of an interface method (Signature),
   467  	// its params or results (Tuples), or their immediate
   468  	// elements (mostly Slice, Pointer, Basic, Named),
   469  	// so there's no need to optimize anything else.
   470  	switch t := t.(type) {
   471  	case *aliases.Alias:
   472  		return h.shallowHash(t.Underlying())
   473  
   474  	case *types.Signature:
   475  		var hash uint32 = 604171
   476  		if t.Variadic() {
   477  			hash *= 971767
   478  		}
   479  		// The Signature/Tuple recursion is always finite
   480  		// and invariably shallow.
   481  		return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results())
   482  
   483  	case *types.Tuple:
   484  		n := t.Len()
   485  		hash := 9137 + 2*uint32(n)
   486  		for i := 0; i < n; i++ {
   487  			hash += 53471161 * h.shallowHash(t.At(i).Type())
   488  		}
   489  		return hash
   490  
   491  	case *types.Basic:
   492  		return 45212177 * uint32(t.Kind())
   493  
   494  	case *types.Array:
   495  		return 1524181 + 2*uint32(t.Len())
   496  
   497  	case *types.Slice:
   498  		return 2690201
   499  
   500  	case *types.Struct:
   501  		return 3326489
   502  
   503  	case *types.Pointer:
   504  		return 4393139
   505  
   506  	case *types.Union:
   507  		return 562448657
   508  
   509  	case *types.Interface:
   510  		return 2124679 // no recursion here
   511  
   512  	case *types.Map:
   513  		return 9109
   514  
   515  	case *types.Chan:
   516  		return 9127
   517  
   518  	case *types.Named:
   519  		return h.hashPtr(t.Obj())
   520  
   521  	case *types.TypeParam:
   522  		return h.hashPtr(t.Obj())
   523  	}
   524  	panic(fmt.Sprintf("shallowHash: %T: %v", t, t))
   525  }