| // Copyright 2019, The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package cmp | |
| import "reflect" | |
| // valueNode represents a single node within a report, which is a | |
| // structured representation of the value tree, containing information | |
| // regarding which nodes are equal or not. | |
| type valueNode struct { | |
| parent *valueNode | |
| Type reflect.Type | |
| ValueX reflect.Value | |
| ValueY reflect.Value | |
| // NumSame is the number of leaf nodes that are equal. | |
| // All descendants are equal only if NumDiff is 0. | |
| NumSame int | |
| // NumDiff is the number of leaf nodes that are not equal. | |
| NumDiff int | |
| // NumIgnored is the number of leaf nodes that are ignored. | |
| NumIgnored int | |
| // NumCompared is the number of leaf nodes that were compared | |
| // using an Equal method or Comparer function. | |
| NumCompared int | |
| // NumTransformed is the number of non-leaf nodes that were transformed. | |
| NumTransformed int | |
| // NumChildren is the number of transitive descendants of this node. | |
| // This counts from zero; thus, leaf nodes have no descendants. | |
| NumChildren int | |
| // MaxDepth is the maximum depth of the tree. This counts from zero; | |
| // thus, leaf nodes have a depth of zero. | |
| MaxDepth int | |
| // Records is a list of struct fields, slice elements, or map entries. | |
| Records []reportRecord // If populated, implies Value is not populated | |
| // Value is the result of a transformation, pointer indirect, of | |
| // type assertion. | |
| Value *valueNode // If populated, implies Records is not populated | |
| // TransformerName is the name of the transformer. | |
| TransformerName string // If non-empty, implies Value is populated | |
| } | |
| type reportRecord struct { | |
| Key reflect.Value // Invalid for slice element | |
| Value *valueNode | |
| } | |
| func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { | |
| vx, vy := ps.Values() | |
| child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} | |
| switch s := ps.(type) { | |
| case StructField: | |
| assert(parent.Value == nil) | |
| parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) | |
| case SliceIndex: | |
| assert(parent.Value == nil) | |
| parent.Records = append(parent.Records, reportRecord{Value: child}) | |
| case MapIndex: | |
| assert(parent.Value == nil) | |
| parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) | |
| case Indirect: | |
| assert(parent.Value == nil && parent.Records == nil) | |
| parent.Value = child | |
| case TypeAssertion: | |
| assert(parent.Value == nil && parent.Records == nil) | |
| parent.Value = child | |
| case Transform: | |
| assert(parent.Value == nil && parent.Records == nil) | |
| parent.Value = child | |
| parent.TransformerName = s.Name() | |
| parent.NumTransformed++ | |
| default: | |
| assert(parent == nil) // Must be the root step | |
| } | |
| return child | |
| } | |
| func (r *valueNode) Report(rs Result) { | |
| assert(r.MaxDepth == 0) // May only be called on leaf nodes | |
| if rs.ByIgnore() { | |
| r.NumIgnored++ | |
| } else { | |
| if rs.Equal() { | |
| r.NumSame++ | |
| } else { | |
| r.NumDiff++ | |
| } | |
| } | |
| assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) | |
| if rs.ByMethod() { | |
| r.NumCompared++ | |
| } | |
| if rs.ByFunc() { | |
| r.NumCompared++ | |
| } | |
| assert(r.NumCompared <= 1) | |
| } | |
| func (child *valueNode) PopStep() (parent *valueNode) { | |
| if child.parent == nil { | |
| return nil | |
| } | |
| parent = child.parent | |
| parent.NumSame += child.NumSame | |
| parent.NumDiff += child.NumDiff | |
| parent.NumIgnored += child.NumIgnored | |
| parent.NumCompared += child.NumCompared | |
| parent.NumTransformed += child.NumTransformed | |
| parent.NumChildren += child.NumChildren + 1 | |
| if parent.MaxDepth < child.MaxDepth+1 { | |
| parent.MaxDepth = child.MaxDepth + 1 | |
| } | |
| return parent | |
| } |