1
0
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:
Russ Cox 2009-07-01 16:45:09 -07:00
parent 25706fec19
commit a439f66228
3 changed files with 37 additions and 10 deletions

View File

@ -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 },

View File

@ -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);
}

View File

@ -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,