github.com/niubaoshu/goutils@v0.0.0-20180828035119-e8e576f66c2b/deepequal.go (about) 1 package goutils 2 3 import ( 4 "reflect" 5 "sync" 6 "sync/atomic" 7 "time" 8 "unsafe" 9 ) 10 11 // Copyright 2009 The Go Authors. All rights reserved. 12 // Use of this source code is governed by a BSD-style 13 // license that can be found in the LICENSE file. 14 15 // Deep equality test via reflection 16 17 // During deepValueEqual, must keep track of checks that are 18 // in progress. The comparison algorithm assumes that all 19 // checks in progress are true when it reencounters them. 20 // Visited comparisons are stored in a map indexed by visit. 21 type visit struct { 22 a1 unsafe.Pointer 23 a2 unsafe.Pointer 24 typ reflect.Type 25 } 26 27 type ( 28 Comparer struct { 29 mu sync.RWMutex 30 visited map[visit]bool 31 funcs atomic.Value 32 } 33 comparers map[reflect.Type]func(v1, v2 interface{}) bool 34 ) 35 36 func (c *Comparer) Add(rt reflect.Type, fn func(interface{}, interface{}) bool) { 37 c.mu.Lock() 38 fs := c.funcs.Load().(comparers) 39 nfs := make(comparers) 40 for k, v := range fs { 41 nfs[k] = v 42 } 43 nfs[rt] = fn 44 c.funcs.Store(nfs) 45 c.mu.Unlock() 46 } 47 48 func NewComparer() *Comparer { 49 c := &Comparer{ 50 visited: make(map[visit]bool), 51 } 52 c.funcs.Store( 53 comparers(map[reflect.Type]func(interface{}, interface{}) bool{ 54 reflect.TypeOf((*time.Time)(nil)).Elem(): func(v1 interface{}, v2 interface{}) bool { 55 return v1.(time.Time).Equal(v2.(time.Time)) 56 }, 57 }), 58 ) 59 return c 60 } 61 62 // Tests for deep equality using reflected types. The map argument tracks 63 // comparisons that have already been seen, which allows short circuiting on 64 // recursive types. 65 func (c *Comparer) deepValueEqual(v1, v2 reflect.Value, depth int) bool { 66 if !v1.IsValid() || !v2.IsValid() { 67 return v1.IsValid() == v2.IsValid() 68 } 69 if v1.Type() != v2.Type() { 70 return false 71 } 72 73 if fn, ok := c.funcs.Load().(comparers)[v1.Type()]; ok { 74 return fn(valueInterface(v1, false), valueInterface(v2, false)) 75 } 76 77 // if depth > 10 { panic("deepValueEqual") } // for debugging 78 79 // We want to avoid putting more in the visited map than we need to. 80 // For any possible reference cycle that might be encountered, 81 // hard(t) needs to return true for at least one of the types in the cycle. 82 hard := func(k reflect.Kind) bool { 83 switch k { 84 case reflect.Map, reflect.Slice, reflect.Ptr, reflect.Interface: 85 return true 86 } 87 return false 88 } 89 90 if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { 91 addr1 := unsafe.Pointer(v1.UnsafeAddr()) 92 addr2 := unsafe.Pointer(v2.UnsafeAddr()) 93 if uintptr(addr1) > uintptr(addr2) { 94 // Canonicalize order to reduce number of entries in visited. 95 // Assumes non-moving garbage collector. 96 addr1, addr2 = addr2, addr1 97 } 98 99 // Short circuit if references are already seen. 100 typ := v1.Type() 101 v := visit{addr1, addr2, typ} 102 if c.visited[v] { 103 return true 104 } 105 106 // Remember for later. 107 c.visited[v] = true 108 } 109 110 switch v1.Kind() { 111 case reflect.Array: 112 for i := 0; i < v1.Len(); i++ { 113 if !c.deepValueEqual(v1.Index(i), v2.Index(i), depth+1) { 114 return false 115 } 116 } 117 return true 118 case reflect.Slice: 119 if v1.IsNil() != v2.IsNil() { 120 return false 121 } 122 if v1.Len() != v2.Len() { 123 return false 124 } 125 if v1.Pointer() == v2.Pointer() { 126 return true 127 } 128 for i := 0; i < v1.Len(); i++ { 129 if !c.deepValueEqual(v1.Index(i), v2.Index(i), depth+1) { 130 return false 131 } 132 } 133 return true 134 case reflect.Interface: 135 if v1.IsNil() || v2.IsNil() { 136 return v1.IsNil() == v2.IsNil() 137 } 138 return c.deepValueEqual(v1.Elem(), v2.Elem(), depth+1) 139 case reflect.Ptr: 140 if v1.Pointer() == v2.Pointer() { 141 return true 142 } 143 return c.deepValueEqual(v1.Elem(), v2.Elem(), depth+1) 144 case reflect.Struct: 145 for i, n := 0, v1.NumField(); i < n; i++ { 146 if !c.deepValueEqual(v1.Field(i), v2.Field(i), depth+1) { 147 return false 148 } 149 } 150 return true 151 case reflect.Map: 152 if v1.IsNil() != v2.IsNil() { 153 return false 154 } 155 if v1.Len() != v2.Len() { 156 return false 157 } 158 if v1.Pointer() == v2.Pointer() { 159 return true 160 } 161 if v1.Type().Key().Kind() == reflect.Ptr { 162 dupv2 := reflect.ValueOf(DeepClone(valueInterface(v2, false))) 163 for _, k1 := range v1.MapKeys() { 164 if !k1.IsValid() { 165 return false 166 } 167 lookup := false 168 for _, dk2 := range dupv2.MapKeys() { 169 if dk2.IsValid() && c.deepValueEqual(k1, dk2, depth+1) { 170 val1 := v1.MapIndex(k1) 171 val2 := dupv2.MapIndex(dk2) 172 if val1.IsValid() && val2.IsValid() && c.deepValueEqual(val1, val2, depth+1) { 173 dupv2.SetMapIndex(dk2, reflect.Value{}) 174 lookup = true 175 break 176 } 177 } 178 } 179 if !lookup { 180 return false 181 } 182 } 183 return true 184 } 185 for _, k1 := range v1.MapKeys() { 186 val1 := v1.MapIndex(k1) 187 val2 := v2.MapIndex(k1) 188 if !val1.IsValid() || !val2.IsValid() || !c.deepValueEqual(val1, val2, depth+1) { 189 return false 190 } 191 } 192 return true 193 case reflect.Func: 194 if v1.IsNil() && v2.IsNil() { 195 return true 196 } 197 // Can't do better than this: 198 return false 199 default: 200 // Normal equality suffices 201 return valueInterface(v1, false) == valueInterface(v2, false) 202 } 203 } 204 205 //go:linkname valueInterface reflect.valueInterface 206 func valueInterface(v reflect.Value, safe bool) interface{} 207 208 // DeepEqual reports whether x and y are ``deeply equal,'' defined as follows. 209 // Two values of identical type are deeply equal if one of the following cases applies. 210 // Values of distinct types are never deeply equal. 211 // 212 // Array values are deeply equal when their corresponding elements are deeply equal. 213 // 214 // Struct values are deeply equal if their corresponding fields, 215 // both exported and unexported, are deeply equal. 216 // 217 // Func values are deeply equal if both are nil; otherwise they are not deeply equal. 218 // 219 // Interface values are deeply equal if they hold deeply equal concrete values. 220 // 221 // Map values are deeply equal when all of the following are true: 222 // they are both nil or both non-nil, they have the same length, 223 // and either they are the same map object or their corresponding keys 224 // (matched using Go equality) map to deeply equal values. 225 // 226 // Pointer values are deeply equal if they are equal using Go's == operator 227 // or if they point to deeply equal values. 228 // 229 // Slice values are deeply equal when all of the following are true: 230 // they are both nil or both non-nil, they have the same length, 231 // and either they point to the same initial entry of the same underlying array 232 // (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. 233 // Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) 234 // are not deeply equal. 235 // 236 // Other values - numbers, bools, strings, and channels - are deeply equal 237 // if they are equal using Go's == operator. 238 // 239 // In general DeepEqual is a recursive relaxation of Go's == operator. 240 // However, this idea is impossible to implement without some inconsistency. 241 // Specifically, it is possible for a value to be unequal to itself, 242 // either because it is of func type (uncomparable in general) 243 // or because it is a floating-point NaN value (not equal to itself in floating-point comparison), 244 // or because it is an array, struct, or interface containing 245 // such a value. 246 // On the other hand, pointer values are always equal to themselves, 247 // even if they point at or contain such problematic values, 248 // because they compare equal using Go's == operator, and that 249 // is a sufficient condition to be deeply equal, regardless of content. 250 // DeepEqual has been defined so that the same short-cut applies 251 // to slices and maps: if x and y are the same slice or the same map, 252 // they are deeply equal regardless of content. 253 func (c *Comparer) DeepEqual(x, y interface{}) bool { 254 if x == nil || y == nil { 255 return x == y 256 } 257 v1 := reflect.ValueOf(x) 258 v2 := reflect.ValueOf(y) 259 if v1.Type() != v2.Type() { 260 return false 261 } 262 return c.deepValueEqual(v1, v2, 0) 263 }