mirror of
https://github.com/golang/go
synced 2024-11-20 04:54:44 -07:00
add test, fix bug: structs that differ in their
first field were not being handled correctly because the visited map did not include the type. R=r OCL=31006 CL=31006
This commit is contained in:
parent
25706fec19
commit
a439f66228
@ -420,6 +420,7 @@ var deepEqualTests = []DeepEqualTest {
|
||||
DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 3 }, true },
|
||||
DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.5 }, true },
|
||||
DeepEqualTest{ os.Error(nil), os.Error(nil), true },
|
||||
|
||||
// Inequalities
|
||||
DeepEqualTest{ 1, 2, false },
|
||||
DeepEqualTest{ int32(1), int32(2), false },
|
||||
@ -429,6 +430,8 @@ var deepEqualTests = []DeepEqualTest {
|
||||
DeepEqualTest{ make([]int, 10), make([]int, 11), false },
|
||||
DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 4 }, false },
|
||||
DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.6 }, false },
|
||||
DeepEqualTest{ Basic{ 1, 0 }, Basic{ 2, 0 }, false },
|
||||
|
||||
// Mismatched types
|
||||
DeepEqualTest{ 1, 1.0, false },
|
||||
DeepEqualTest{ int32(1), int64(1), false },
|
||||
|
@ -8,33 +8,57 @@ package reflect
|
||||
|
||||
import "reflect"
|
||||
|
||||
// During deepValueEqual, must keep track of checks that are
|
||||
// in progress. The comparison algorithm assumes that all
|
||||
// checks in progress are true when it reencounters them.
|
||||
// Visited are stored in a map indexed by 17 * a1 + a2;
|
||||
type visit struct {
|
||||
a1 uintptr;
|
||||
a2 uintptr;
|
||||
typ Type;
|
||||
next *visit;
|
||||
}
|
||||
|
||||
// Tests for deep equality using reflected types. The map argument tracks
|
||||
// comparisons that have already been seen, which allows short circuiting on
|
||||
// recursive types.
|
||||
func deepValueEqual(v1, v2 Value, visited map[Addr]Addr, depth int) bool {
|
||||
func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
|
||||
if v1 == nil {
|
||||
return v2 == nil
|
||||
}
|
||||
if v2 == nil {
|
||||
return false
|
||||
}
|
||||
if v1.Kind() != v2.Kind() {
|
||||
if !equalType(v1.Type(), v2.Type()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if depth > 10 { panic("deepValueEqual") } // for debugging
|
||||
|
||||
// Short circuit if references are identical or already seen
|
||||
addr1 := v1.Addr();
|
||||
addr2 := v2.Addr();
|
||||
addr1 := uintptr(v1.Addr());
|
||||
addr2 := uintptr(v2.Addr());
|
||||
if addr1 > addr2 {
|
||||
// Canonicalize order to reduce number of entries in visited.
|
||||
addr1, addr2 = addr2, addr1;
|
||||
}
|
||||
|
||||
// Short circuit if references are identical ...
|
||||
if addr1 == addr2 {
|
||||
return true;
|
||||
}
|
||||
if vaddr, ok := visited[addr1]; ok && vaddr == addr2 {
|
||||
return true;
|
||||
|
||||
// ... or already seen
|
||||
h := 17 * addr1 + addr2;
|
||||
seen, ok := visited[h];
|
||||
typ := v1.Type();
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
visited[addr1] = addr2;
|
||||
|
||||
// Remember for later.
|
||||
visited[h] = &visit{addr1, addr2, typ, seen};
|
||||
|
||||
switch v1.Kind() {
|
||||
case ArrayKind:
|
||||
@ -91,5 +115,5 @@ func DeepEqual(a1, a2 interface{}) bool {
|
||||
if !equalType(v1.Type(), v2.Type()) {
|
||||
return false;
|
||||
}
|
||||
return deepValueEqual(v1, v2, make(map[Addr]Addr), 0);
|
||||
return deepValueEqual(v1, v2, make(map[uintptr]*visit), 0);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
type Addr unsafe.Pointer
|
||||
|
||||
func equalType(a, b Type) bool {
|
||||
return a.String() == b.String()
|
||||
return a.Kind() == b.Kind() && a.String() == b.String()
|
||||
}
|
||||
|
||||
// Value is the generic interface to reflection values. Once its Kind is known,
|
||||
|
Loading…
Reference in New Issue
Block a user