mirror of
https://github.com/golang/go
synced 2024-11-13 12:20:26 -07:00
unique: handle zero-size types
Fixes #69458 Change-Id: Ic7fda7f556522780b2819138dfc1277137398692 Reviewed-on: https://go-review.googlesource.com/c/go/+/613397 Reviewed-by: Carlos Amedee <carlos@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
parent
aa06c94054
commit
2927aa10ab
@ -10,9 +10,11 @@ import (
|
|||||||
"internal/weak"
|
"internal/weak"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
_ "unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zero uintptr
|
||||||
|
|
||||||
// Handle is a globally unique identity for some value of type T.
|
// 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
|
// Two handles compare equal exactly if the two values used to create the handles
|
||||||
@ -32,6 +34,9 @@ func (h Handle[T]) Value() T {
|
|||||||
func Make[T comparable](value T) Handle[T] {
|
func Make[T comparable](value T) Handle[T] {
|
||||||
// Find the map for type T.
|
// Find the map for type T.
|
||||||
typ := abi.TypeFor[T]()
|
typ := abi.TypeFor[T]()
|
||||||
|
if typ.Size() == 0 {
|
||||||
|
return Handle[T]{(*T)(unsafe.Pointer(&zero))}
|
||||||
|
}
|
||||||
ma, ok := uniqueMaps.Load(typ)
|
ma, ok := uniqueMaps.Load(typ)
|
||||||
if !ok {
|
if !ok {
|
||||||
// This is a good time to initialize cleanup, since we must go through
|
// This is a good time to initialize cleanup, since we must go through
|
||||||
|
@ -31,6 +31,7 @@ type testStruct struct {
|
|||||||
z float64
|
z float64
|
||||||
b string
|
b string
|
||||||
}
|
}
|
||||||
|
type testZeroSize struct{}
|
||||||
|
|
||||||
func TestHandle(t *testing.T) {
|
func TestHandle(t *testing.T) {
|
||||||
testHandle(t, testString("foo"))
|
testHandle(t, testString("foo"))
|
||||||
@ -45,6 +46,7 @@ func TestHandle(t *testing.T) {
|
|||||||
})
|
})
|
||||||
testHandle(t, testStruct{0.5, "184"})
|
testHandle(t, testStruct{0.5, "184"})
|
||||||
testHandle(t, testEface("hello"))
|
testHandle(t, testEface("hello"))
|
||||||
|
testHandle(t, testZeroSize(struct{}{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHandle[T comparable](t *testing.T, value T) {
|
func testHandle[T comparable](t *testing.T, value T) {
|
||||||
@ -65,15 +67,19 @@ func testHandle[T comparable](t *testing.T, value T) {
|
|||||||
t.Error("v0 != v1")
|
t.Error("v0 != v1")
|
||||||
}
|
}
|
||||||
|
|
||||||
drainMaps(t)
|
drainMaps[T](t)
|
||||||
checkMapsFor(t, value)
|
checkMapsFor(t, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// drainMaps ensures that the internal maps are drained.
|
// drainMaps ensures that the internal maps are drained.
|
||||||
func drainMaps(t *testing.T) {
|
func drainMaps[T comparable](t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
if unsafe.Sizeof(*(new(T))) == 0 {
|
||||||
|
return // zero-size types are not inserted.
|
||||||
|
}
|
||||||
|
|
||||||
wait := make(chan struct{}, 1)
|
wait := make(chan struct{}, 1)
|
||||||
|
|
||||||
// Set up a one-time notification for the next time the cleanup runs.
|
// Set up a one-time notification for the next time the cleanup runs.
|
||||||
|
Loading…
Reference in New Issue
Block a user