github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/ssa/interp/testdata/src/reflect/deepequal.go (about) 1 package reflect 2 3 // Not an actual implementation of DeepEqual. This is a model that supports 4 // the bare minimum needed to get through testing interp. 5 // 6 // Does not handle cycles. 7 // 8 // Note: unclear if reflect.go can support this. 9 func DeepEqual(x, y interface{}) bool { 10 if x == nil || y == nil { 11 return x == y 12 } 13 v1 := ValueOf(x) 14 v2 := ValueOf(y) 15 16 return deepValueEqual(v1, v2, make(map[visit]bool)) 17 } 18 19 // Key for the visitedMap in deepValueEqual. 20 type visit struct { 21 a1, a2 uintptr 22 typ Type 23 } 24 25 func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { 26 if !v1.IsValid() || !v2.IsValid() { 27 return v1.IsValid() == v2.IsValid() 28 } 29 if v1.Type() != v2.Type() { 30 return false 31 } 32 33 // Short circuit on reference types that can lead to cycles in comparison. 34 switch v1.Kind() { 35 case Pointer, Map, Slice, Interface: 36 k := visit{v1.Pointer(), v2.Pointer(), v1.Type()} // Not safe for moving GC. 37 if visited[k] { 38 // The comparison algorithm assumes that all checks in progress are true when it reencounters them. 39 return true 40 } 41 visited[k] = true 42 } 43 44 switch v1.Kind() { 45 case Array: 46 for i := 0; i < v1.Len(); i++ { 47 if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { 48 return false 49 } 50 } 51 return true 52 case Slice: 53 if v1.IsNil() != v2.IsNil() { 54 return false 55 } 56 if v1.Len() != v2.Len() { 57 return false 58 } 59 if v1.Pointer() == v2.Pointer() { 60 return true 61 } 62 for i := 0; i < v1.Len(); i++ { 63 if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { 64 return false 65 } 66 } 67 return true 68 case Interface: 69 if v1.IsNil() || v2.IsNil() { 70 return v1.IsNil() == v2.IsNil() 71 } 72 return deepValueEqual(v1.Elem(), v2.Elem(), visited) 73 case Ptr: 74 if v1.Pointer() == v2.Pointer() { 75 return true 76 } 77 return deepValueEqual(v1.Elem(), v2.Elem(), visited) 78 case Struct: 79 for i, n := 0, v1.NumField(); i < n; i++ { 80 if !deepValueEqual(v1.Field(i), v2.Field(i), visited) { 81 return false 82 } 83 } 84 return true 85 case Map: 86 if v1.IsNil() != v2.IsNil() { 87 return false 88 } 89 if v1.Len() != v2.Len() { 90 return false 91 } 92 if v1.Pointer() == v2.Pointer() { 93 return true 94 } 95 for _, k := range v1.MapKeys() { 96 val1 := v1.MapIndex(k) 97 val2 := v2.MapIndex(k) 98 if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) { 99 return false 100 } 101 } 102 return true 103 case Func: 104 return v1.IsNil() && v2.IsNil() 105 default: 106 // Normal equality suffices 107 return v1.Interface() == v2.Interface() // try interface comparison as a fallback. 108 } 109 }