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

« back to all changes in this revision

Viewing changes to testing/checkers/deepequal.go

  • Committer: Daniele Stroppa
  • Date: 2014-01-08 15:58:10 UTC
  • mfrom: (1953.1.231 juju-core)
  • Revision ID: daniele.stroppa@joyent.com-20140108155810-xecbwrqkb5i0fyoe
Merging trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}