summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-07-01 16:45:09 -0700
committerRuss Cox <rsc@golang.org>2009-07-01 16:45:09 -0700
commitf2bf1a2f1b708cb3bde96da7f4bcbd49f2067eb1 (patch)
tree2fd0332e9edde805bdd8d1b3e7f9d88b6dc6c4ae
parent249dc7c0008210ccdd66bbddfde1cdee6a18643f (diff)
downloadgolang-f2bf1a2f1b708cb3bde96da7f4bcbd49f2067eb1.tar.gz
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
-rw-r--r--src/pkg/reflect/all_test.go3
-rw-r--r--src/pkg/reflect/deepequal.go42
-rw-r--r--src/pkg/reflect/value.go2
3 files changed, 37 insertions, 10 deletions
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 9cfc7e268..fcbe473be 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -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 },
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index 0195a43a6..d4299edb5 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -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);
}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 61410af99..f59e3a272 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -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,