| // Copyright 2024 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 unique | |
| import ( | |
| "internal/abi" | |
| isync "internal/sync" | |
| "unsafe" | |
| ) | |
| var zero uintptr | |
| // Handle is a globally unique identity for some value of type T. | |
| // | |
| // Two handles compare equal exactly if the two values used to create the handles | |
| // would have also compared equal. The comparison of two handles is trivial and | |
| // typically much more efficient than comparing the values used to create them. | |
| type Handle[T comparable] struct { | |
| value *T | |
| } | |
| // Value returns a shallow copy of the T value that produced the Handle. | |
| // Value is safe for concurrent use by multiple goroutines. | |
| func (h Handle[T]) Value() T { | |
| return *h.value | |
| } | |
| // Make returns a globally unique handle for a value of type T. Handles | |
| // are equal if and only if the values used to produce them are equal. | |
| // Make is safe for concurrent use by multiple goroutines. | |
| func Make[T comparable](value T) Handle[T] { | |
| // Find the map for type T. | |
| typ := abi.TypeFor[T]() | |
| if typ.Size() == 0 { | |
| return Handle[T]{(*T)(unsafe.Pointer(&zero))} | |
| } | |
| ma, ok := uniqueMaps.Load(typ) | |
| if !ok { | |
| m := &uniqueMap[T]{canonMap: newCanonMap[T](), cloneSeq: makeCloneSeq(typ)} | |
| ma, _ = uniqueMaps.LoadOrStore(typ, m) | |
| } | |
| m := ma.(*uniqueMap[T]) | |
| // Find the value in the map. | |
| ptr := m.Load(value) | |
| if ptr == nil { | |
| // Insert a new value into the map. | |
| ptr = m.LoadOrStore(clone(value, &m.cloneSeq)) | |
| } | |
| return Handle[T]{ptr} | |
| } | |
| // uniqueMaps is an index of type-specific concurrent maps used for unique.Make. | |
| // | |
| // The two-level map might seem odd at first since the HashTrieMap could have "any" | |
| // as its key type, but the issue is escape analysis. We do not want to force lookups | |
| // to escape the argument, and using a type-specific map allows us to avoid that where | |
| // possible (for example, for strings and plain-ol'-data structs). We also get the | |
| // benefit of not cramming every different type into a single map, but that's certainly | |
| // not enough to outweigh the cost of two map lookups. What is worth it though, is saving | |
| // on those allocations. | |
| var uniqueMaps isync.HashTrieMap[*abi.Type, any] // any is always a *uniqueMap[T]. | |
| type uniqueMap[T comparable] struct { | |
| *canonMap[T] | |
| cloneSeq | |
| } |