!+
(x, y reflect.Value, seen map[comparison]bool)
| 13 | |
| 14 | //!+ |
| 15 | func equal(x, y reflect.Value, seen map[comparison]bool) bool { |
| 16 | if !x.IsValid() || !y.IsValid() { |
| 17 | return x.IsValid() == y.IsValid() |
| 18 | } |
| 19 | if x.Type() != y.Type() { |
| 20 | return false |
| 21 | } |
| 22 | |
| 23 | // ...cycle check omitted (shown later)... |
| 24 | |
| 25 | //!- |
| 26 | //!+cyclecheck |
| 27 | // cycle check |
| 28 | if x.CanAddr() && y.CanAddr() { |
| 29 | xptr := unsafe.Pointer(x.UnsafeAddr()) |
| 30 | yptr := unsafe.Pointer(y.UnsafeAddr()) |
| 31 | if xptr == yptr { |
| 32 | return true // identical references |
| 33 | } |
| 34 | c := comparison{xptr, yptr, x.Type()} |
| 35 | if seen[c] { |
| 36 | return true // already seen |
| 37 | } |
| 38 | seen[c] = true |
| 39 | } |
| 40 | //!-cyclecheck |
| 41 | //!+ |
| 42 | switch x.Kind() { |
| 43 | case reflect.Bool: |
| 44 | return x.Bool() == y.Bool() |
| 45 | |
| 46 | case reflect.String: |
| 47 | return x.String() == y.String() |
| 48 | |
| 49 | // ...numeric cases omitted for brevity... |
| 50 | |
| 51 | //!- |
| 52 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, |
| 53 | reflect.Int64: |
| 54 | return x.Int() == y.Int() |
| 55 | |
| 56 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, |
| 57 | reflect.Uint64, reflect.Uintptr: |
| 58 | return x.Uint() == y.Uint() |
| 59 | |
| 60 | case reflect.Float32, reflect.Float64: |
| 61 | return x.Float() == y.Float() |
| 62 | |
| 63 | case reflect.Complex64, reflect.Complex128: |
| 64 | return x.Complex() == y.Complex() |
| 65 | //!+ |
| 66 | case reflect.Chan, reflect.UnsafePointer, reflect.Func: |
| 67 | return x.Pointer() == y.Pointer() |
| 68 | |
| 69 | case reflect.Ptr, reflect.Interface: |
| 70 | return equal(x.Elem(), y.Elem(), seen) |
| 71 | |
| 72 | case reflect.Array, reflect.Slice: |