github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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  }