13 // DeepEqual is similar to reflect.DeepEqual, but treats nil as equal
14 // to empty maps and slices. Some of the implementation is cribbed
15 // from Go's reflect package.
16 func DeepEqual(x, y interface{}) bool {
17 vx := reflect.ValueOf(x)
18 vy := reflect.ValueOf(y)
19 return deepValueEqual(vx, vy, make(map[visit]bool))
22 func deepValueEqual(x, y reflect.Value, visited map[visit]bool) bool {
23 if isEmpty(x) && isEmpty(y) {
40 case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
41 if x.CanAddr() && y.CanAddr() {
42 a1 := unsafe.Pointer(x.UnsafeAddr())
43 a2 := unsafe.Pointer(y.UnsafeAddr())
44 if uintptr(a1) > uintptr(a2) {
45 // Canonicalize order to reduce number of entries in visited.
46 // Assumes non-moving garbage collector.
49 v := visit{a1, a2, tx}
59 return x.Bool() == y.Bool()
61 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
62 return x.Int() == y.Int()
64 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
65 return x.Uint() == y.Uint()
67 case reflect.Float32, reflect.Float64:
68 return x.Float() == y.Float()
70 case reflect.Complex64, reflect.Complex128:
71 return x.Complex() == y.Complex()
74 return x.String() == y.String()
77 for i := 0; i < tx.Len(); i++ {
78 if !deepValueEqual(x.Index(i), y.Index(i), visited) {
90 if x.Len() != y.Len() {
93 for i := 0; i < x.Len(); i++ {
94 if !deepValueEqual(x.Index(i), y.Index(i), visited) {
100 case reflect.Interface:
107 return deepValueEqual(x.Elem(), y.Elem(), visited)
110 if x.Pointer() == y.Pointer() {
113 return deepValueEqual(x.Elem(), y.Elem(), visited)
116 for i := 0; i < tx.NumField(); i++ {
117 if !deepValueEqual(x.Field(i), y.Field(i), visited) {
124 if x.Pointer() == y.Pointer() {
127 if x.Len() != y.Len() {
130 for _, k := range x.MapKeys() {
131 if !deepValueEqual(x.MapIndex(k), y.MapIndex(k), visited) {
138 return x.IsNil() && y.IsNil()
143 func isEmpty(v reflect.Value) bool {
147 switch v.Type().Kind() {
148 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
151 case reflect.Slice, reflect.Map:
152 return v.IsNil() || v.Len() == 0