1
0
mirror of https://github.com/golang/go synced 2024-11-22 00:04:41 -07:00

add reflect.Typeof; test for and fix nil interface bug in DeepEqual

R=r
DELTA=40  (30 added, 2 deleted, 8 changed)
OCL=30742
CL=30753
This commit is contained in:
Russ Cox 2009-06-25 14:25:38 -07:00
parent 6af5775d74
commit 4866223c2e
3 changed files with 38 additions and 10 deletions

View File

@ -419,6 +419,7 @@ var deepEqualTests = []DeepEqualTest {
DeepEqualTest{ make([]int, 10), make([]int, 10), true },
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 },
@ -445,6 +446,16 @@ func TestDeepEqual(t *testing.T) {
}
}
func TestTypeof(t *testing.T) {
for i, test := range deepEqualTests {
v := NewValue(test.a);
typ := Typeof(test.a);
if typ != v.Type() {
t.Errorf("Typeof(%v) = %v, but NewValue(%v).Type() = %v", test.a, typ, test.a, v.Type());
}
}
}
func TestDeepEqualRecursiveStruct(t *testing.T) {
a, b := new(Recursive), new(Recursive);
*a = Recursive{ 12, a };

View File

@ -11,7 +11,7 @@ import "reflect"
// 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) bool {
func deepValueEqual(v1, v2 Value, visited map[Addr]Addr, depth int) bool {
if v1 == nil {
return v2 == nil
}
@ -22,6 +22,8 @@ func deepValueEqual(v1, v2 Value, visited map[Addr]Addr) bool {
return false;
}
// if depth > 10 { panic("deepValueEqual") } // for debugging
// Short circuit if references are identical or already seen
addr1 := v1.Addr();
addr2 := v2.Addr();
@ -42,19 +44,23 @@ func deepValueEqual(v1, v2 Value, visited map[Addr]Addr) bool {
return false;
}
for i := 0; i < arr1.Len(); i++ {
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited) {
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
return false;
}
}
return true;
case InterfaceKind:
return deepValueEqual(NewValue(v1.(InterfaceValue).Get()),
NewValue(v2.(InterfaceValue).Get()), visited);
i1 := v1.(InterfaceValue).Get();
i2 := v2.(InterfaceValue).Get();
if i1 == nil || i2 == nil {
return i1 == i2;
}
return deepValueEqual(NewValue(i1), NewValue(i2), visited, depth+1);
case MapKind:
// TODO(dnadasi): Implement this fully once MapValue is implemented
return v1.Interface() == v2.Interface();
case PtrKind:
return deepValueEqual(v1.(PtrValue).Sub(), v2.(PtrValue).Sub(), visited);
return deepValueEqual(v1.(PtrValue).Sub(), v2.(PtrValue).Sub(), visited, depth+1);
case StructKind:
struct1 := v1.(StructValue);
struct2 := v2.(StructValue);
@ -62,7 +68,7 @@ func deepValueEqual(v1, v2 Value, visited map[Addr]Addr) bool {
return false;
}
for i := 0; i < struct1.Len(); i++ {
if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited) {
if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited, depth+1) {
return false;
}
}
@ -85,5 +91,5 @@ func DeepEqual(a1, a2 interface{}) bool {
if !equalType(v1.Type(), v2.Type()) {
return false;
}
return deepValueEqual(v1, v2, make(map[Addr]Addr));
return deepValueEqual(v1, v2, make(map[Addr]Addr), 0);
}

View File

@ -942,9 +942,7 @@ func copyArray(dst ArrayValue, src ArrayValue, n int) {
}
}
// NewValue creates a new Value from the interface{} object provided.
func NewValue(e interface {}) Value {
value, typestring, indir := unsafe.Reflect(e);
func typeof(typestring string) Type {
typ, ok := typecache[typestring];
if !ok {
typ = ParseTypeString("", typestring);
@ -958,6 +956,13 @@ func NewValue(e interface {}) Value {
}
typecache[typestring] = typ;
}
return typ;
}
// NewValue creates a new Value from the interface{} object provided.
func NewValue(e interface {}) Value {
value, typestring, indir := unsafe.Reflect(e);
typ := typeof(typestring);
var ap Addr;
if indir {
// Content of interface is large and didn't
@ -984,6 +989,12 @@ func NewValue(e interface {}) Value {
return newValueAddr(typ, ap);
}
// Typeof returns the type of the value in the interface{} object provided.
func Typeof(e interface{}) Type {
value, typestring, indir := unsafe.Reflect(e);
return typeof(typestring);
}
// Indirect indirects one level through a value, if it is a pointer.
// If not a pointer, the value is returned unchanged.
// Useful when walking arbitrary data structures.