github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/reflect/deepequal.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Deep equality test via reflection
     6  
     7  package reflect
     8  
     9  import "unsafe"
    10  
    11  // During deepValueEqual, must keep track of checks that are
    12  // in progress.  The comparison algorithm assumes that all
    13  // checks in progress are true when it reencounters them.
    14  // Visited comparisons are stored in a map indexed by visit.
    15  type visit struct {
    16  	a1  unsafe.Pointer
    17  	a2  unsafe.Pointer
    18  	typ Type
    19  }
    20  
    21  // Tests for deep equality using reflected types. The map argument tracks
    22  // comparisons that have already been seen, which allows short circuiting on
    23  // recursive types.
    24  func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
    25  	if !v1.IsValid() || !v2.IsValid() {
    26  		return v1.IsValid() == v2.IsValid()
    27  	}
    28  	if v1.Type() != v2.Type() {
    29  		return false
    30  	}
    31  
    32  	// if depth > 10 { panic("deepValueEqual") }	// for debugging
    33  	hard := func(k Kind) bool {
    34  		switch k {
    35  		case Array, Map, Slice, Struct:
    36  			return true
    37  		}
    38  		return false
    39  	}
    40  
    41  	if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
    42  		addr1 := unsafe.Pointer(v1.UnsafeAddr())
    43  		addr2 := unsafe.Pointer(v2.UnsafeAddr())
    44  		if uintptr(addr1) > uintptr(addr2) {
    45  			// Canonicalize order to reduce number of entries in visited.
    46  			addr1, addr2 = addr2, addr1
    47  		}
    48  
    49  		// Short circuit if references are identical ...
    50  		if addr1 == addr2 {
    51  			return true
    52  		}
    53  
    54  		// ... or already seen
    55  		typ := v1.Type()
    56  		v := visit{addr1, addr2, typ}
    57  		if visited[v] {
    58  			return true
    59  		}
    60  
    61  		// Remember for later.
    62  		visited[v] = true
    63  	}
    64  
    65  	switch v1.Kind() {
    66  	case Array:
    67  		for i := 0; i < v1.Len(); i++ {
    68  			if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
    69  				return false
    70  			}
    71  		}
    72  		return true
    73  	case Slice:
    74  		if v1.IsNil() != v2.IsNil() {
    75  			return false
    76  		}
    77  		if v1.Len() != v2.Len() {
    78  			return false
    79  		}
    80  		if v1.Pointer() == v2.Pointer() {
    81  			return true
    82  		}
    83  		for i := 0; i < v1.Len(); i++ {
    84  			if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
    85  				return false
    86  			}
    87  		}
    88  		return true
    89  	case Interface:
    90  		if v1.IsNil() || v2.IsNil() {
    91  			return v1.IsNil() == v2.IsNil()
    92  		}
    93  		return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
    94  	case Ptr:
    95  		return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
    96  	case Struct:
    97  		for i, n := 0, v1.NumField(); i < n; i++ {
    98  			if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
    99  				return false
   100  			}
   101  		}
   102  		return true
   103  	case Map:
   104  		if v1.IsNil() != v2.IsNil() {
   105  			return false
   106  		}
   107  		if v1.Len() != v2.Len() {
   108  			return false
   109  		}
   110  		if v1.Pointer() == v2.Pointer() {
   111  			return true
   112  		}
   113  		for _, k := range v1.MapKeys() {
   114  			if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
   115  				return false
   116  			}
   117  		}
   118  		return true
   119  	case Func:
   120  		if v1.IsNil() && v2.IsNil() {
   121  			return true
   122  		}
   123  		// Can't do better than this:
   124  		return false
   125  	default:
   126  		// Normal equality suffices
   127  		return valueInterface(v1, false) == valueInterface(v2, false)
   128  	}
   129  }
   130  
   131  // DeepEqual tests for deep equality. It uses normal == equality where
   132  // possible but will scan elements of arrays, slices, maps, and fields of
   133  // structs. In maps, keys are compared with == but elements use deep
   134  // equality. DeepEqual correctly handles recursive types. Functions are equal
   135  // only if they are both nil.
   136  // An empty slice is not equal to a nil slice.
   137  func DeepEqual(a1, a2 interface{}) bool {
   138  	if a1 == nil || a2 == nil {
   139  		return a1 == a2
   140  	}
   141  	v1 := ValueOf(a1)
   142  	v2 := ValueOf(a2)
   143  	if v1.Type() != v2.Type() {
   144  		return false
   145  	}
   146  	return deepValueEqual(v1, v2, make(map[visit]bool), 0)
   147  }