~dstroppa/juju-core/joyent-provider-storage

1953.139.1 by Roger Peppe
testing/checkers: implement DeepEquals
1
// Copied with small adaptations from the reflect package in the
2
// Go source tree.
3
4
// Copyright 2009 The Go Authors. All rights reserved.
5
// Use of this source code is governed by a BSD-style
6
// license that can be found in the LICENSE file.
7
8
// Deep equality test via reflection
9
10
package checkers
11
12
import "reflect"
13
14
// During deepValueEqual, must keep track of checks that are
15
// in progress.  The comparison algorithm assumes that all
16
// checks in progress are true when it reencounters them.
17
// Visited comparisons are stored in a map indexed by visit.
18
type visit struct {
19
	a1  uintptr
20
	a2  uintptr
21
	typ reflect.Type
22
}
23
24
// Tests for deep equality using reflected types. The map argument tracks
25
// comparisons that have already been seen, which allows short circuiting on
26
// recursive types.
27
func deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
28
	if !v1.IsValid() || !v2.IsValid() {
29
		return v1.IsValid() == v2.IsValid()
30
	}
31
	if v1.Type() != v2.Type() {
32
		return false
33
	}
34
35
	// if depth > 10 { panic("deepValueEqual") }	// for debugging
36
	hard := func(k reflect.Kind) bool {
37
		switch k {
38
		case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
39
			return true
40
		}
41
		return false
42
	}
43
44
	if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
45
		addr1 := v1.UnsafeAddr()
46
		addr2 := v2.UnsafeAddr()
47
		if addr1 > addr2 {
48
			// Canonicalize order to reduce number of entries in visited.
49
			addr1, addr2 = addr2, addr1
50
		}
51
52
		// Short circuit if references are identical ...
53
		if addr1 == addr2 {
54
			return true
55
		}
56
57
		// ... or already seen
58
		typ := v1.Type()
59
		v := visit{addr1, addr2, typ}
60
		if visited[v] {
61
			return true
62
		}
63
64
		// Remember for later.
65
		visited[v] = true
66
	}
67
68
	switch v1.Kind() {
69
	case reflect.Array:
70
		if v1.Len() != v2.Len() {
71
			return false
72
		}
73
		for i := 0; i < v1.Len(); i++ {
74
			if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
75
				return false
76
			}
77
		}
78
		return true
79
	case reflect.Slice:
80
		// No check for nil == nil here.
81
82
		if v1.Len() != v2.Len() {
83
			return false
84
		}
85
		if v1.Pointer() == v2.Pointer() {
86
			return true
87
		}
88
		for i := 0; i < v1.Len(); i++ {
89
			if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
90
				return false
91
			}
92
		}
93
		return true
94
	case reflect.Interface:
95
		if v1.IsNil() || v2.IsNil() {
96
			return v1.IsNil() == v2.IsNil()
97
		}
98
		return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
99
	case reflect.Ptr:
100
		return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
101
	case reflect.Struct:
102
		for i, n := 0, v1.NumField(); i < n; i++ {
103
			if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
104
				return false
105
			}
106
		}
107
		return true
108
	case reflect.Map:
109
		// No check for nil == nil here.
110
111
		if v1.Len() != v2.Len() {
112
			return false
113
		}
114
		if v1.Pointer() == v2.Pointer() {
115
			return true
116
		}
117
		for _, k := range v1.MapKeys() {
118
			if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
119
				return false
120
			}
121
		}
122
		return true
123
	case reflect.Func:
124
		if v1.IsNil() && v2.IsNil() {
125
			return true
126
		}
127
		// Can't do better than this:
128
		return false
129
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
130
		return v1.Int() == v2.Int()
131
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
132
		return v1.Uint() == v2.Uint()
133
	case reflect.Float32, reflect.Float64:
134
		return v1.Float() == v2.Float()
135
	case reflect.Complex64, reflect.Complex128:
136
		return v1.Complex() == v2.Complex()
137
	case reflect.Bool:
138
		return v1.Bool() == v2.Bool()
139
	case reflect.String:
140
		return v1.String() == v2.String()
141
	case reflect.Chan, reflect.UnsafePointer:
142
		return v1.Pointer() == v2.Pointer()
143
	default:
144
		panic("unexpected type " + v1.Type().String())
145
	}
146
}
147
148
// DeepEqual tests for deep equality. It uses normal == equality where
149
// possible but will scan elements of arrays, slices, maps, and fields of
150
// structs. In maps, keys are compared with == but elements use deep
151
// equality. DeepEqual correctly handles recursive types. Functions are equal
152
// only if they are both nil.
153
// DeepEqual differs from reflect.DeepEqual in that an empty
154
// slice is equal to a nil slice, and an empty map is equal to a nil map.
155
func DeepEqual(a1, a2 interface{}) bool {
156
	if a1 == nil || a2 == nil {
157
		return a1 == a2
158
	}
159
	v1 := reflect.ValueOf(a1)
160
	v2 := reflect.ValueOf(a2)
161
	if v1.Type() != v2.Type() {
162
		return false
163
	}
164
	return deepValueEqual(v1, v2, make(map[visit]bool), 0)
165
}