1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundakpackage cmp 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport ( 8*88d15eacSSasha Smundak "fmt" 9*88d15eacSSasha Smundak "reflect" 10*88d15eacSSasha Smundak "strings" 11*88d15eacSSasha Smundak "unicode" 12*88d15eacSSasha Smundak "unicode/utf8" 13*88d15eacSSasha Smundak 14*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp/internal/value" 15*88d15eacSSasha Smundak) 16*88d15eacSSasha Smundak 17*88d15eacSSasha Smundak// Path is a list of PathSteps describing the sequence of operations to get 18*88d15eacSSasha Smundak// from some root type to the current position in the value tree. 19*88d15eacSSasha Smundak// The first Path element is always an operation-less PathStep that exists 20*88d15eacSSasha Smundak// simply to identify the initial type. 21*88d15eacSSasha Smundak// 22*88d15eacSSasha Smundak// When traversing structs with embedded structs, the embedded struct will 23*88d15eacSSasha Smundak// always be accessed as a field before traversing the fields of the 24*88d15eacSSasha Smundak// embedded struct themselves. That is, an exported field from the 25*88d15eacSSasha Smundak// embedded struct will never be accessed directly from the parent struct. 26*88d15eacSSasha Smundaktype Path []PathStep 27*88d15eacSSasha Smundak 28*88d15eacSSasha Smundak// PathStep is a union-type for specific operations to traverse 29*88d15eacSSasha Smundak// a value's tree structure. Users of this package never need to implement 30*88d15eacSSasha Smundak// these types as values of this type will be returned by this package. 31*88d15eacSSasha Smundak// 32*88d15eacSSasha Smundak// Implementations of this interface are 33*88d15eacSSasha Smundak// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. 34*88d15eacSSasha Smundaktype PathStep interface { 35*88d15eacSSasha Smundak String() string 36*88d15eacSSasha Smundak 37*88d15eacSSasha Smundak // Type is the resulting type after performing the path step. 38*88d15eacSSasha Smundak Type() reflect.Type 39*88d15eacSSasha Smundak 40*88d15eacSSasha Smundak // Values is the resulting values after performing the path step. 41*88d15eacSSasha Smundak // The type of each valid value is guaranteed to be identical to Type. 42*88d15eacSSasha Smundak // 43*88d15eacSSasha Smundak // In some cases, one or both may be invalid or have restrictions: 44*88d15eacSSasha Smundak // - For StructField, both are not interface-able if the current field 45*88d15eacSSasha Smundak // is unexported and the struct type is not explicitly permitted by 46*88d15eacSSasha Smundak // an Exporter to traverse unexported fields. 47*88d15eacSSasha Smundak // - For SliceIndex, one may be invalid if an element is missing from 48*88d15eacSSasha Smundak // either the x or y slice. 49*88d15eacSSasha Smundak // - For MapIndex, one may be invalid if an entry is missing from 50*88d15eacSSasha Smundak // either the x or y map. 51*88d15eacSSasha Smundak // 52*88d15eacSSasha Smundak // The provided values must not be mutated. 53*88d15eacSSasha Smundak Values() (vx, vy reflect.Value) 54*88d15eacSSasha Smundak} 55*88d15eacSSasha Smundak 56*88d15eacSSasha Smundakvar ( 57*88d15eacSSasha Smundak _ PathStep = StructField{} 58*88d15eacSSasha Smundak _ PathStep = SliceIndex{} 59*88d15eacSSasha Smundak _ PathStep = MapIndex{} 60*88d15eacSSasha Smundak _ PathStep = Indirect{} 61*88d15eacSSasha Smundak _ PathStep = TypeAssertion{} 62*88d15eacSSasha Smundak _ PathStep = Transform{} 63*88d15eacSSasha Smundak) 64*88d15eacSSasha Smundak 65*88d15eacSSasha Smundakfunc (pa *Path) push(s PathStep) { 66*88d15eacSSasha Smundak *pa = append(*pa, s) 67*88d15eacSSasha Smundak} 68*88d15eacSSasha Smundak 69*88d15eacSSasha Smundakfunc (pa *Path) pop() { 70*88d15eacSSasha Smundak *pa = (*pa)[:len(*pa)-1] 71*88d15eacSSasha Smundak} 72*88d15eacSSasha Smundak 73*88d15eacSSasha Smundak// Last returns the last PathStep in the Path. 74*88d15eacSSasha Smundak// If the path is empty, this returns a non-nil PathStep that reports a nil Type. 75*88d15eacSSasha Smundakfunc (pa Path) Last() PathStep { 76*88d15eacSSasha Smundak return pa.Index(-1) 77*88d15eacSSasha Smundak} 78*88d15eacSSasha Smundak 79*88d15eacSSasha Smundak// Index returns the ith step in the Path and supports negative indexing. 80*88d15eacSSasha Smundak// A negative index starts counting from the tail of the Path such that -1 81*88d15eacSSasha Smundak// refers to the last step, -2 refers to the second-to-last step, and so on. 82*88d15eacSSasha Smundak// If index is invalid, this returns a non-nil PathStep that reports a nil Type. 83*88d15eacSSasha Smundakfunc (pa Path) Index(i int) PathStep { 84*88d15eacSSasha Smundak if i < 0 { 85*88d15eacSSasha Smundak i = len(pa) + i 86*88d15eacSSasha Smundak } 87*88d15eacSSasha Smundak if i < 0 || i >= len(pa) { 88*88d15eacSSasha Smundak return pathStep{} 89*88d15eacSSasha Smundak } 90*88d15eacSSasha Smundak return pa[i] 91*88d15eacSSasha Smundak} 92*88d15eacSSasha Smundak 93*88d15eacSSasha Smundak// String returns the simplified path to a node. 94*88d15eacSSasha Smundak// The simplified path only contains struct field accesses. 95*88d15eacSSasha Smundak// 96*88d15eacSSasha Smundak// For example: 97*88d15eacSSasha Smundak// 98*88d15eacSSasha Smundak// MyMap.MySlices.MyField 99*88d15eacSSasha Smundakfunc (pa Path) String() string { 100*88d15eacSSasha Smundak var ss []string 101*88d15eacSSasha Smundak for _, s := range pa { 102*88d15eacSSasha Smundak if _, ok := s.(StructField); ok { 103*88d15eacSSasha Smundak ss = append(ss, s.String()) 104*88d15eacSSasha Smundak } 105*88d15eacSSasha Smundak } 106*88d15eacSSasha Smundak return strings.TrimPrefix(strings.Join(ss, ""), ".") 107*88d15eacSSasha Smundak} 108*88d15eacSSasha Smundak 109*88d15eacSSasha Smundak// GoString returns the path to a specific node using Go syntax. 110*88d15eacSSasha Smundak// 111*88d15eacSSasha Smundak// For example: 112*88d15eacSSasha Smundak// 113*88d15eacSSasha Smundak// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField 114*88d15eacSSasha Smundakfunc (pa Path) GoString() string { 115*88d15eacSSasha Smundak var ssPre, ssPost []string 116*88d15eacSSasha Smundak var numIndirect int 117*88d15eacSSasha Smundak for i, s := range pa { 118*88d15eacSSasha Smundak var nextStep PathStep 119*88d15eacSSasha Smundak if i+1 < len(pa) { 120*88d15eacSSasha Smundak nextStep = pa[i+1] 121*88d15eacSSasha Smundak } 122*88d15eacSSasha Smundak switch s := s.(type) { 123*88d15eacSSasha Smundak case Indirect: 124*88d15eacSSasha Smundak numIndirect++ 125*88d15eacSSasha Smundak pPre, pPost := "(", ")" 126*88d15eacSSasha Smundak switch nextStep.(type) { 127*88d15eacSSasha Smundak case Indirect: 128*88d15eacSSasha Smundak continue // Next step is indirection, so let them batch up 129*88d15eacSSasha Smundak case StructField: 130*88d15eacSSasha Smundak numIndirect-- // Automatic indirection on struct fields 131*88d15eacSSasha Smundak case nil: 132*88d15eacSSasha Smundak pPre, pPost = "", "" // Last step; no need for parenthesis 133*88d15eacSSasha Smundak } 134*88d15eacSSasha Smundak if numIndirect > 0 { 135*88d15eacSSasha Smundak ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) 136*88d15eacSSasha Smundak ssPost = append(ssPost, pPost) 137*88d15eacSSasha Smundak } 138*88d15eacSSasha Smundak numIndirect = 0 139*88d15eacSSasha Smundak continue 140*88d15eacSSasha Smundak case Transform: 141*88d15eacSSasha Smundak ssPre = append(ssPre, s.trans.name+"(") 142*88d15eacSSasha Smundak ssPost = append(ssPost, ")") 143*88d15eacSSasha Smundak continue 144*88d15eacSSasha Smundak } 145*88d15eacSSasha Smundak ssPost = append(ssPost, s.String()) 146*88d15eacSSasha Smundak } 147*88d15eacSSasha Smundak for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { 148*88d15eacSSasha Smundak ssPre[i], ssPre[j] = ssPre[j], ssPre[i] 149*88d15eacSSasha Smundak } 150*88d15eacSSasha Smundak return strings.Join(ssPre, "") + strings.Join(ssPost, "") 151*88d15eacSSasha Smundak} 152*88d15eacSSasha Smundak 153*88d15eacSSasha Smundaktype pathStep struct { 154*88d15eacSSasha Smundak typ reflect.Type 155*88d15eacSSasha Smundak vx, vy reflect.Value 156*88d15eacSSasha Smundak} 157*88d15eacSSasha Smundak 158*88d15eacSSasha Smundakfunc (ps pathStep) Type() reflect.Type { return ps.typ } 159*88d15eacSSasha Smundakfunc (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } 160*88d15eacSSasha Smundakfunc (ps pathStep) String() string { 161*88d15eacSSasha Smundak if ps.typ == nil { 162*88d15eacSSasha Smundak return "<nil>" 163*88d15eacSSasha Smundak } 164*88d15eacSSasha Smundak s := value.TypeString(ps.typ, false) 165*88d15eacSSasha Smundak if s == "" || strings.ContainsAny(s, "{}\n") { 166*88d15eacSSasha Smundak return "root" // Type too simple or complex to print 167*88d15eacSSasha Smundak } 168*88d15eacSSasha Smundak return fmt.Sprintf("{%s}", s) 169*88d15eacSSasha Smundak} 170*88d15eacSSasha Smundak 171*88d15eacSSasha Smundak// StructField represents a struct field access on a field called Name. 172*88d15eacSSasha Smundaktype StructField struct{ *structField } 173*88d15eacSSasha Smundaktype structField struct { 174*88d15eacSSasha Smundak pathStep 175*88d15eacSSasha Smundak name string 176*88d15eacSSasha Smundak idx int 177*88d15eacSSasha Smundak 178*88d15eacSSasha Smundak // These fields are used for forcibly accessing an unexported field. 179*88d15eacSSasha Smundak // pvx, pvy, and field are only valid if unexported is true. 180*88d15eacSSasha Smundak unexported bool 181*88d15eacSSasha Smundak mayForce bool // Forcibly allow visibility 182*88d15eacSSasha Smundak paddr bool // Was parent addressable? 183*88d15eacSSasha Smundak pvx, pvy reflect.Value // Parent values (always addressable) 184*88d15eacSSasha Smundak field reflect.StructField // Field information 185*88d15eacSSasha Smundak} 186*88d15eacSSasha Smundak 187*88d15eacSSasha Smundakfunc (sf StructField) Type() reflect.Type { return sf.typ } 188*88d15eacSSasha Smundakfunc (sf StructField) Values() (vx, vy reflect.Value) { 189*88d15eacSSasha Smundak if !sf.unexported { 190*88d15eacSSasha Smundak return sf.vx, sf.vy // CanInterface reports true 191*88d15eacSSasha Smundak } 192*88d15eacSSasha Smundak 193*88d15eacSSasha Smundak // Forcibly obtain read-write access to an unexported struct field. 194*88d15eacSSasha Smundak if sf.mayForce { 195*88d15eacSSasha Smundak vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr) 196*88d15eacSSasha Smundak vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr) 197*88d15eacSSasha Smundak return vx, vy // CanInterface reports true 198*88d15eacSSasha Smundak } 199*88d15eacSSasha Smundak return sf.vx, sf.vy // CanInterface reports false 200*88d15eacSSasha Smundak} 201*88d15eacSSasha Smundakfunc (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } 202*88d15eacSSasha Smundak 203*88d15eacSSasha Smundak// Name is the field name. 204*88d15eacSSasha Smundakfunc (sf StructField) Name() string { return sf.name } 205*88d15eacSSasha Smundak 206*88d15eacSSasha Smundak// Index is the index of the field in the parent struct type. 207*88d15eacSSasha Smundak// See reflect.Type.Field. 208*88d15eacSSasha Smundakfunc (sf StructField) Index() int { return sf.idx } 209*88d15eacSSasha Smundak 210*88d15eacSSasha Smundak// SliceIndex is an index operation on a slice or array at some index Key. 211*88d15eacSSasha Smundaktype SliceIndex struct{ *sliceIndex } 212*88d15eacSSasha Smundaktype sliceIndex struct { 213*88d15eacSSasha Smundak pathStep 214*88d15eacSSasha Smundak xkey, ykey int 215*88d15eacSSasha Smundak isSlice bool // False for reflect.Array 216*88d15eacSSasha Smundak} 217*88d15eacSSasha Smundak 218*88d15eacSSasha Smundakfunc (si SliceIndex) Type() reflect.Type { return si.typ } 219*88d15eacSSasha Smundakfunc (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } 220*88d15eacSSasha Smundakfunc (si SliceIndex) String() string { 221*88d15eacSSasha Smundak switch { 222*88d15eacSSasha Smundak case si.xkey == si.ykey: 223*88d15eacSSasha Smundak return fmt.Sprintf("[%d]", si.xkey) 224*88d15eacSSasha Smundak case si.ykey == -1: 225*88d15eacSSasha Smundak // [5->?] means "I don't know where X[5] went" 226*88d15eacSSasha Smundak return fmt.Sprintf("[%d->?]", si.xkey) 227*88d15eacSSasha Smundak case si.xkey == -1: 228*88d15eacSSasha Smundak // [?->3] means "I don't know where Y[3] came from" 229*88d15eacSSasha Smundak return fmt.Sprintf("[?->%d]", si.ykey) 230*88d15eacSSasha Smundak default: 231*88d15eacSSasha Smundak // [5->3] means "X[5] moved to Y[3]" 232*88d15eacSSasha Smundak return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) 233*88d15eacSSasha Smundak } 234*88d15eacSSasha Smundak} 235*88d15eacSSasha Smundak 236*88d15eacSSasha Smundak// Key is the index key; it may return -1 if in a split state 237*88d15eacSSasha Smundakfunc (si SliceIndex) Key() int { 238*88d15eacSSasha Smundak if si.xkey != si.ykey { 239*88d15eacSSasha Smundak return -1 240*88d15eacSSasha Smundak } 241*88d15eacSSasha Smundak return si.xkey 242*88d15eacSSasha Smundak} 243*88d15eacSSasha Smundak 244*88d15eacSSasha Smundak// SplitKeys are the indexes for indexing into slices in the 245*88d15eacSSasha Smundak// x and y values, respectively. These indexes may differ due to the 246*88d15eacSSasha Smundak// insertion or removal of an element in one of the slices, causing 247*88d15eacSSasha Smundak// all of the indexes to be shifted. If an index is -1, then that 248*88d15eacSSasha Smundak// indicates that the element does not exist in the associated slice. 249*88d15eacSSasha Smundak// 250*88d15eacSSasha Smundak// Key is guaranteed to return -1 if and only if the indexes returned 251*88d15eacSSasha Smundak// by SplitKeys are not the same. SplitKeys will never return -1 for 252*88d15eacSSasha Smundak// both indexes. 253*88d15eacSSasha Smundakfunc (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } 254*88d15eacSSasha Smundak 255*88d15eacSSasha Smundak// MapIndex is an index operation on a map at some index Key. 256*88d15eacSSasha Smundaktype MapIndex struct{ *mapIndex } 257*88d15eacSSasha Smundaktype mapIndex struct { 258*88d15eacSSasha Smundak pathStep 259*88d15eacSSasha Smundak key reflect.Value 260*88d15eacSSasha Smundak} 261*88d15eacSSasha Smundak 262*88d15eacSSasha Smundakfunc (mi MapIndex) Type() reflect.Type { return mi.typ } 263*88d15eacSSasha Smundakfunc (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } 264*88d15eacSSasha Smundakfunc (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) } 265*88d15eacSSasha Smundak 266*88d15eacSSasha Smundak// Key is the value of the map key. 267*88d15eacSSasha Smundakfunc (mi MapIndex) Key() reflect.Value { return mi.key } 268*88d15eacSSasha Smundak 269*88d15eacSSasha Smundak// Indirect represents pointer indirection on the parent type. 270*88d15eacSSasha Smundaktype Indirect struct{ *indirect } 271*88d15eacSSasha Smundaktype indirect struct { 272*88d15eacSSasha Smundak pathStep 273*88d15eacSSasha Smundak} 274*88d15eacSSasha Smundak 275*88d15eacSSasha Smundakfunc (in Indirect) Type() reflect.Type { return in.typ } 276*88d15eacSSasha Smundakfunc (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } 277*88d15eacSSasha Smundakfunc (in Indirect) String() string { return "*" } 278*88d15eacSSasha Smundak 279*88d15eacSSasha Smundak// TypeAssertion represents a type assertion on an interface. 280*88d15eacSSasha Smundaktype TypeAssertion struct{ *typeAssertion } 281*88d15eacSSasha Smundaktype typeAssertion struct { 282*88d15eacSSasha Smundak pathStep 283*88d15eacSSasha Smundak} 284*88d15eacSSasha Smundak 285*88d15eacSSasha Smundakfunc (ta TypeAssertion) Type() reflect.Type { return ta.typ } 286*88d15eacSSasha Smundakfunc (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } 287*88d15eacSSasha Smundakfunc (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } 288*88d15eacSSasha Smundak 289*88d15eacSSasha Smundak// Transform is a transformation from the parent type to the current type. 290*88d15eacSSasha Smundaktype Transform struct{ *transform } 291*88d15eacSSasha Smundaktype transform struct { 292*88d15eacSSasha Smundak pathStep 293*88d15eacSSasha Smundak trans *transformer 294*88d15eacSSasha Smundak} 295*88d15eacSSasha Smundak 296*88d15eacSSasha Smundakfunc (tf Transform) Type() reflect.Type { return tf.typ } 297*88d15eacSSasha Smundakfunc (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } 298*88d15eacSSasha Smundakfunc (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } 299*88d15eacSSasha Smundak 300*88d15eacSSasha Smundak// Name is the name of the Transformer. 301*88d15eacSSasha Smundakfunc (tf Transform) Name() string { return tf.trans.name } 302*88d15eacSSasha Smundak 303*88d15eacSSasha Smundak// Func is the function pointer to the transformer function. 304*88d15eacSSasha Smundakfunc (tf Transform) Func() reflect.Value { return tf.trans.fnc } 305*88d15eacSSasha Smundak 306*88d15eacSSasha Smundak// Option returns the originally constructed Transformer option. 307*88d15eacSSasha Smundak// The == operator can be used to detect the exact option used. 308*88d15eacSSasha Smundakfunc (tf Transform) Option() Option { return tf.trans } 309*88d15eacSSasha Smundak 310*88d15eacSSasha Smundak// pointerPath represents a dual-stack of pointers encountered when 311*88d15eacSSasha Smundak// recursively traversing the x and y values. This data structure supports 312*88d15eacSSasha Smundak// detection of cycles and determining whether the cycles are equal. 313*88d15eacSSasha Smundak// In Go, cycles can occur via pointers, slices, and maps. 314*88d15eacSSasha Smundak// 315*88d15eacSSasha Smundak// The pointerPath uses a map to represent a stack; where descension into a 316*88d15eacSSasha Smundak// pointer pushes the address onto the stack, and ascension from a pointer 317*88d15eacSSasha Smundak// pops the address from the stack. Thus, when traversing into a pointer from 318*88d15eacSSasha Smundak// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles 319*88d15eacSSasha Smundak// by checking whether the pointer has already been visited. The cycle detection 320*88d15eacSSasha Smundak// uses a separate stack for the x and y values. 321*88d15eacSSasha Smundak// 322*88d15eacSSasha Smundak// If a cycle is detected we need to determine whether the two pointers 323*88d15eacSSasha Smundak// should be considered equal. The definition of equality chosen by Equal 324*88d15eacSSasha Smundak// requires two graphs to have the same structure. To determine this, both the 325*88d15eacSSasha Smundak// x and y values must have a cycle where the previous pointers were also 326*88d15eacSSasha Smundak// encountered together as a pair. 327*88d15eacSSasha Smundak// 328*88d15eacSSasha Smundak// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and 329*88d15eacSSasha Smundak// MapIndex with pointer information for the x and y values. 330*88d15eacSSasha Smundak// Suppose px and py are two pointers to compare, we then search the 331*88d15eacSSasha Smundak// Path for whether px was ever encountered in the Path history of x, and 332*88d15eacSSasha Smundak// similarly so with py. If either side has a cycle, the comparison is only 333*88d15eacSSasha Smundak// equal if both px and py have a cycle resulting from the same PathStep. 334*88d15eacSSasha Smundak// 335*88d15eacSSasha Smundak// Using a map as a stack is more performant as we can perform cycle detection 336*88d15eacSSasha Smundak// in O(1) instead of O(N) where N is len(Path). 337*88d15eacSSasha Smundaktype pointerPath struct { 338*88d15eacSSasha Smundak // mx is keyed by x pointers, where the value is the associated y pointer. 339*88d15eacSSasha Smundak mx map[value.Pointer]value.Pointer 340*88d15eacSSasha Smundak // my is keyed by y pointers, where the value is the associated x pointer. 341*88d15eacSSasha Smundak my map[value.Pointer]value.Pointer 342*88d15eacSSasha Smundak} 343*88d15eacSSasha Smundak 344*88d15eacSSasha Smundakfunc (p *pointerPath) Init() { 345*88d15eacSSasha Smundak p.mx = make(map[value.Pointer]value.Pointer) 346*88d15eacSSasha Smundak p.my = make(map[value.Pointer]value.Pointer) 347*88d15eacSSasha Smundak} 348*88d15eacSSasha Smundak 349*88d15eacSSasha Smundak// Push indicates intent to descend into pointers vx and vy where 350*88d15eacSSasha Smundak// visited reports whether either has been seen before. If visited before, 351*88d15eacSSasha Smundak// equal reports whether both pointers were encountered together. 352*88d15eacSSasha Smundak// Pop must be called if and only if the pointers were never visited. 353*88d15eacSSasha Smundak// 354*88d15eacSSasha Smundak// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map 355*88d15eacSSasha Smundak// and be non-nil. 356*88d15eacSSasha Smundakfunc (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) { 357*88d15eacSSasha Smundak px := value.PointerOf(vx) 358*88d15eacSSasha Smundak py := value.PointerOf(vy) 359*88d15eacSSasha Smundak _, ok1 := p.mx[px] 360*88d15eacSSasha Smundak _, ok2 := p.my[py] 361*88d15eacSSasha Smundak if ok1 || ok2 { 362*88d15eacSSasha Smundak equal = p.mx[px] == py && p.my[py] == px // Pointers paired together 363*88d15eacSSasha Smundak return equal, true 364*88d15eacSSasha Smundak } 365*88d15eacSSasha Smundak p.mx[px] = py 366*88d15eacSSasha Smundak p.my[py] = px 367*88d15eacSSasha Smundak return false, false 368*88d15eacSSasha Smundak} 369*88d15eacSSasha Smundak 370*88d15eacSSasha Smundak// Pop ascends from pointers vx and vy. 371*88d15eacSSasha Smundakfunc (p pointerPath) Pop(vx, vy reflect.Value) { 372*88d15eacSSasha Smundak delete(p.mx, value.PointerOf(vx)) 373*88d15eacSSasha Smundak delete(p.my, value.PointerOf(vy)) 374*88d15eacSSasha Smundak} 375*88d15eacSSasha Smundak 376*88d15eacSSasha Smundak// isExported reports whether the identifier is exported. 377*88d15eacSSasha Smundakfunc isExported(id string) bool { 378*88d15eacSSasha Smundak r, _ := utf8.DecodeRuneInString(id) 379*88d15eacSSasha Smundak return unicode.IsUpper(r) 380*88d15eacSSasha Smundak} 381