mirror of https://github.com/golang/go.git
Merge ff903bb099 into 49cdf0c42e
This commit is contained in:
commit
e647daab4a
|
|
@ -1056,6 +1056,30 @@ func init() {
|
||||||
cycleMap2["cycle"] = cycleMap2
|
cycleMap2["cycle"] = cycleMap2
|
||||||
cycleMap3 = map[string]any{}
|
cycleMap3 = map[string]any{}
|
||||||
cycleMap3["different"] = cycleMap3
|
cycleMap3["different"] = cycleMap3
|
||||||
|
|
||||||
|
p1.b = append(p1.b, p2, p1, p1)
|
||||||
|
p2.b = append(p2.b, p1, p2, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
type slicePtr struct {
|
||||||
|
b []*slicePtr
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
p1 = new(slicePtr)
|
||||||
|
p2 = new(slicePtr)
|
||||||
|
)
|
||||||
|
|
||||||
|
type structFloat64 struct {
|
||||||
|
D float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type structFloat32 struct {
|
||||||
|
D float32
|
||||||
|
}
|
||||||
|
|
||||||
|
type structChanInt32 struct {
|
||||||
|
D chan int32
|
||||||
}
|
}
|
||||||
|
|
||||||
var deepEqualTests = []DeepEqualTest{
|
var deepEqualTests = []DeepEqualTest{
|
||||||
|
|
@ -1075,6 +1099,10 @@ var deepEqualTests = []DeepEqualTest{
|
||||||
{[]byte{1, 2, 3}, []byte{1, 2, 3}, true},
|
{[]byte{1, 2, 3}, []byte{1, 2, 3}, true},
|
||||||
{[]MyByte{1, 2, 3}, []MyByte{1, 2, 3}, true},
|
{[]MyByte{1, 2, 3}, []MyByte{1, 2, 3}, true},
|
||||||
{MyBytes{1, 2, 3}, MyBytes{1, 2, 3}, true},
|
{MyBytes{1, 2, 3}, MyBytes{1, 2, 3}, true},
|
||||||
|
{[]int32{1, 2, 3}, []int32{1, 2, 3}, true},
|
||||||
|
{p1, p2, true},
|
||||||
|
{[]*int{ptr(1), ptr(2)}, []*int{ptr(1), ptr(2)}, true},
|
||||||
|
{[]int32{1, 2, 3, 4}[:3], []int32{1, 2, 3, 5}[:3], true},
|
||||||
|
|
||||||
// Inequalities
|
// Inequalities
|
||||||
{1, 2, false},
|
{1, 2, false},
|
||||||
|
|
@ -1096,6 +1124,9 @@ var deepEqualTests = []DeepEqualTest{
|
||||||
{fn3, fn3, false},
|
{fn3, fn3, false},
|
||||||
{[][]int{{1}}, [][]int{{2}}, false},
|
{[][]int{{1}}, [][]int{{2}}, false},
|
||||||
{&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false},
|
{&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false},
|
||||||
|
{[]int32{1, 2, 3}, []int32{2, 1, 3}, false},
|
||||||
|
{[]*int{ptr(1), ptr(2)}, []*int{ptr(2), ptr(1)}, false},
|
||||||
|
{[]int32{1, 2, 3, 4}, []int32{1, 2, 3, 5}, false},
|
||||||
|
|
||||||
// Fun with floating point.
|
// Fun with floating point.
|
||||||
{math.NaN(), math.NaN(), false},
|
{math.NaN(), math.NaN(), false},
|
||||||
|
|
@ -1133,6 +1164,60 @@ var deepEqualTests = []DeepEqualTest{
|
||||||
{&loopy1, &loopy2, true},
|
{&loopy1, &loopy2, true},
|
||||||
{&cycleMap1, &cycleMap2, true},
|
{&cycleMap1, &cycleMap2, true},
|
||||||
{&cycleMap1, &cycleMap3, false},
|
{&cycleMap1, &cycleMap3, false},
|
||||||
|
|
||||||
|
// struct slice and StructOf slice
|
||||||
|
{[]structFloat64{structFloat64{D: negativeZero[float64]()}}, []structFloat64{structFloat64{D: 0}}, true},
|
||||||
|
{
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structFloat64]()), setStructOfField("D", negativeZero[float64]()))},
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structFloat64]()), setStructOfField("D", float64(0)))},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{[]structFloat32{structFloat32{D: negativeZero[float32]()}}, []structFloat32{structFloat32{D: 0}}, true},
|
||||||
|
{
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structFloat32]()), setStructOfField("D", negativeZero[float32]()))},
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structFloat32]()), setStructOfField("D", float32(0)))},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{[]structChanInt32{structChanInt32{D: make(chan int32)}}, []structChanInt32{structChanInt32{D: make(chan int32)}}, false},
|
||||||
|
{
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structChanInt32]()), setStructOfField("D", make(chan int32)))},
|
||||||
|
[]any{newStructOf(VisibleFields(TypeFor[structChanInt32]()), setStructOfField("D", make(chan int32)))},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptr[T any](a T) *T {
|
||||||
|
return &a
|
||||||
|
}
|
||||||
|
|
||||||
|
type fieldSet func(Value)
|
||||||
|
|
||||||
|
// newStructOf call StructOf get typ
|
||||||
|
// use typ new any value
|
||||||
|
// use set change new any value
|
||||||
|
func newStructOf(field []StructField, set ...fieldSet) (ret any) {
|
||||||
|
typ := StructOf(field)
|
||||||
|
rret := New(typ).Elem()
|
||||||
|
for _, f := range set {
|
||||||
|
f(rret)
|
||||||
|
}
|
||||||
|
return rret.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setStructOfField set a field of the struct represented by reflect.Value
|
||||||
|
func setStructOfField(fieldName string, fieldValue any) func(Value) {
|
||||||
|
return func(v Value) {
|
||||||
|
field := v.FieldByName(fieldName)
|
||||||
|
field.Set(ValueOf(fieldValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func negativeZero[T float32 | float64]() T {
|
||||||
|
var f T
|
||||||
|
f = -f
|
||||||
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeepEqual(t *testing.T) {
|
func TestDeepEqual(t *testing.T) {
|
||||||
|
|
@ -1274,6 +1359,8 @@ var deepEqualPerfTests = []struct {
|
||||||
|
|
||||||
{x: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}, y: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}},
|
{x: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}, y: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}},
|
||||||
{x: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}, y: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}},
|
{x: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}, y: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}},
|
||||||
|
|
||||||
|
{x: make([]int16, 10240), y: make([]int16, 10240)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeepEqualAllocs(t *testing.T) {
|
func TestDeepEqualAllocs(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/abi"
|
||||||
"internal/bytealg"
|
"internal/bytealg"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -99,15 +100,23 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
|
||||||
if v1.IsNil() != v2.IsNil() {
|
if v1.IsNil() != v2.IsNil() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if v1.Len() != v2.Len() {
|
len := v1.Len()
|
||||||
|
if len != v2.Len() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if v1.UnsafePointer() == v2.UnsafePointer() {
|
v1ptr := v1.UnsafePointer()
|
||||||
|
v2ptr := v2.UnsafePointer()
|
||||||
|
if v1ptr == v2ptr {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Special case for []byte, which is common.
|
// Special case raw memory. Particularly, []byte is very common and is handled here.
|
||||||
if v1.Type().Elem().Kind() == Uint8 {
|
elem := v1.typ().Elem()
|
||||||
return bytealg.Equal(v1.Bytes(), v2.Bytes())
|
if isDeepEqualRawMemory(elem) {
|
||||||
|
size := elem.Size_ * uintptr(len)
|
||||||
|
return bytealg.Equal(
|
||||||
|
unsafe.Slice((*byte)(v1ptr), size),
|
||||||
|
unsafe.Slice((*byte)(v2ptr), size),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
for i := 0; i < v1.Len(); i++ {
|
for i := 0; i < v1.Len(); i++ {
|
||||||
if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
|
if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
|
||||||
|
|
@ -175,6 +184,22 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isDeepEqualRawMemory reports whether DeepEqual can compare
|
||||||
|
// two instances of a type by just comparing their raw memory contents.
|
||||||
|
func isDeepEqualRawMemory(typ *abi.Type) (ok bool) {
|
||||||
|
// Note: Here is an incorrect implementation :
|
||||||
|
//
|
||||||
|
// return typ.TFlag&abi.TFlagRegularMemory != 0
|
||||||
|
//
|
||||||
|
// The reason is DeepEqual can't determine whether two pointer values are equal by comparing them byte by byte.
|
||||||
|
// Doing so would report unequal when it shouldn't,
|
||||||
|
// in the case where two pointers are different but point to the same contents
|
||||||
|
// (e.g. two *int32s that point to different int32s,
|
||||||
|
// both of which contain the same value).
|
||||||
|
|
||||||
|
return typ.PtrBytes == 0 && typ.TFlag&abi.TFlagRegularMemory != 0
|
||||||
|
}
|
||||||
|
|
||||||
// DeepEqual reports whether x and y are “deeply equal,” defined as follows.
|
// DeepEqual reports whether x and y are “deeply equal,” defined as follows.
|
||||||
// Two values of identical type are deeply equal if one of the following cases applies.
|
// Two values of identical type are deeply equal if one of the following cases applies.
|
||||||
// Values of distinct types are never deeply equal.
|
// Values of distinct types are never deeply equal.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue