Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / github.com / google / go-cmp@v0.5.1 / cmp / report_compare.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/github.com/google/go-cmp@v0.5.1/cmp/report_compare.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/github.com/google/go-cmp@v0.5.1/cmp/report_compare.go
new file mode 100644 (file)
index 0000000..9e21809
--- /dev/null
@@ -0,0 +1,432 @@
+// 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.md file.
+
+package cmp
+
+import (
+       "fmt"
+       "reflect"
+
+       "github.com/google/go-cmp/cmp/internal/value"
+)
+
+// numContextRecords is the number of surrounding equal records to print.
+const numContextRecords = 2
+
+type diffMode byte
+
+const (
+       diffUnknown   diffMode = 0
+       diffIdentical diffMode = ' '
+       diffRemoved   diffMode = '-'
+       diffInserted  diffMode = '+'
+)
+
+type typeMode int
+
+const (
+       // emitType always prints the type.
+       emitType typeMode = iota
+       // elideType never prints the type.
+       elideType
+       // autoType prints the type only for composite kinds
+       // (i.e., structs, slices, arrays, and maps).
+       autoType
+)
+
+type formatOptions struct {
+       // DiffMode controls the output mode of FormatDiff.
+       //
+       // If diffUnknown,   then produce a diff of the x and y values.
+       // If diffIdentical, then emit values as if they were equal.
+       // If diffRemoved,   then only emit x values (ignoring y values).
+       // If diffInserted,  then only emit y values (ignoring x values).
+       DiffMode diffMode
+
+       // TypeMode controls whether to print the type for the current node.
+       //
+       // As a general rule of thumb, we always print the type of the next node
+       // after an interface, and always elide the type of the next node after
+       // a slice or map node.
+       TypeMode typeMode
+
+       // formatValueOptions are options specific to printing reflect.Values.
+       formatValueOptions
+}
+
+func (opts formatOptions) WithDiffMode(d diffMode) formatOptions {
+       opts.DiffMode = d
+       return opts
+}
+func (opts formatOptions) WithTypeMode(t typeMode) formatOptions {
+       opts.TypeMode = t
+       return opts
+}
+func (opts formatOptions) WithVerbosity(level int) formatOptions {
+       opts.VerbosityLevel = level
+       opts.LimitVerbosity = true
+       return opts
+}
+func (opts formatOptions) verbosity() uint {
+       switch {
+       case opts.VerbosityLevel < 0:
+               return 0
+       case opts.VerbosityLevel > 16:
+               return 16 // some reasonable maximum to avoid shift overflow
+       default:
+               return uint(opts.VerbosityLevel)
+       }
+}
+
+const maxVerbosityPreset = 3
+
+// verbosityPreset modifies the verbosity settings given an index
+// between 0 and maxVerbosityPreset, inclusive.
+func verbosityPreset(opts formatOptions, i int) formatOptions {
+       opts.VerbosityLevel = int(opts.verbosity()) + 2*i
+       if i > 0 {
+               opts.AvoidStringer = true
+       }
+       if i >= maxVerbosityPreset {
+               opts.PrintAddresses = true
+               opts.QualifiedNames = true
+       }
+       return opts
+}
+
+// FormatDiff converts a valueNode tree into a textNode tree, where the later
+// is a textual representation of the differences detected in the former.
+func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) {
+       if opts.DiffMode == diffIdentical {
+               opts = opts.WithVerbosity(1)
+       } else {
+               opts = opts.WithVerbosity(3)
+       }
+
+       // Check whether we have specialized formatting for this node.
+       // This is not necessary, but helpful for producing more readable outputs.
+       if opts.CanFormatDiffSlice(v) {
+               return opts.FormatDiffSlice(v)
+       }
+
+       var parentKind reflect.Kind
+       if v.parent != nil && v.parent.TransformerName == "" {
+               parentKind = v.parent.Type.Kind()
+       }
+
+       // For leaf nodes, format the value based on the reflect.Values alone.
+       if v.MaxDepth == 0 {
+               switch opts.DiffMode {
+               case diffUnknown, diffIdentical:
+                       // Format Equal.
+                       if v.NumDiff == 0 {
+                               outx := opts.FormatValue(v.ValueX, parentKind, ptrs)
+                               outy := opts.FormatValue(v.ValueY, parentKind, ptrs)
+                               if v.NumIgnored > 0 && v.NumSame == 0 {
+                                       return textEllipsis
+                               } else if outx.Len() < outy.Len() {
+                                       return outx
+                               } else {
+                                       return outy
+                               }
+                       }
+
+                       // Format unequal.
+                       assert(opts.DiffMode == diffUnknown)
+                       var list textList
+                       outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs)
+                       outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs)
+                       for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
+                               opts2 := verbosityPreset(opts, i).WithTypeMode(elideType)
+                               outx = opts2.FormatValue(v.ValueX, parentKind, ptrs)
+                               outy = opts2.FormatValue(v.ValueY, parentKind, ptrs)
+                       }
+                       if outx != nil {
+                               list = append(list, textRecord{Diff: '-', Value: outx})
+                       }
+                       if outy != nil {
+                               list = append(list, textRecord{Diff: '+', Value: outy})
+                       }
+                       return opts.WithTypeMode(emitType).FormatType(v.Type, list)
+               case diffRemoved:
+                       return opts.FormatValue(v.ValueX, parentKind, ptrs)
+               case diffInserted:
+                       return opts.FormatValue(v.ValueY, parentKind, ptrs)
+               default:
+                       panic("invalid diff mode")
+               }
+       }
+
+       // Register slice element to support cycle detection.
+       if parentKind == reflect.Slice {
+               ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true)
+               defer ptrs.Pop()
+               defer func() { out = wrapTrunkReferences(ptrRefs, out) }()
+       }
+
+       // Descend into the child value node.
+       if v.TransformerName != "" {
+               out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
+               out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"}
+               return opts.FormatType(v.Type, out)
+       } else {
+               switch k := v.Type.Kind(); k {
+               case reflect.Struct, reflect.Array, reflect.Slice:
+                       out = opts.formatDiffList(v.Records, k, ptrs)
+                       out = opts.FormatType(v.Type, out)
+               case reflect.Map:
+                       // Register map to support cycle detection.
+                       ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
+                       defer ptrs.Pop()
+
+                       out = opts.formatDiffList(v.Records, k, ptrs)
+                       out = wrapTrunkReferences(ptrRefs, out)
+                       out = opts.FormatType(v.Type, out)
+               case reflect.Ptr:
+                       // Register pointer to support cycle detection.
+                       ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
+                       defer ptrs.Pop()
+
+                       out = opts.FormatDiff(v.Value, ptrs)
+                       out = wrapTrunkReferences(ptrRefs, out)
+                       out = &textWrap{Prefix: "&", Value: out}
+               case reflect.Interface:
+                       out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
+               default:
+                       panic(fmt.Sprintf("%v cannot have children", k))
+               }
+               return out
+       }
+}
+
+func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode {
+       // Derive record name based on the data structure kind.
+       var name string
+       var formatKey func(reflect.Value) string
+       switch k {
+       case reflect.Struct:
+               name = "field"
+               opts = opts.WithTypeMode(autoType)
+               formatKey = func(v reflect.Value) string { return v.String() }
+       case reflect.Slice, reflect.Array:
+               name = "element"
+               opts = opts.WithTypeMode(elideType)
+               formatKey = func(reflect.Value) string { return "" }
+       case reflect.Map:
+               name = "entry"
+               opts = opts.WithTypeMode(elideType)
+               formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) }
+       }
+
+       maxLen := -1
+       if opts.LimitVerbosity {
+               if opts.DiffMode == diffIdentical {
+                       maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
+               } else {
+                       maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc...
+               }
+               opts.VerbosityLevel--
+       }
+
+       // Handle unification.
+       switch opts.DiffMode {
+       case diffIdentical, diffRemoved, diffInserted:
+               var list textList
+               var deferredEllipsis bool // Add final "..." to indicate records were dropped
+               for _, r := range recs {
+                       if len(list) == maxLen {
+                               deferredEllipsis = true
+                               break
+                       }
+
+                       // Elide struct fields that are zero value.
+                       if k == reflect.Struct {
+                               var isZero bool
+                               switch opts.DiffMode {
+                               case diffIdentical:
+                                       isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY)
+                               case diffRemoved:
+                                       isZero = value.IsZero(r.Value.ValueX)
+                               case diffInserted:
+                                       isZero = value.IsZero(r.Value.ValueY)
+                               }
+                               if isZero {
+                                       continue
+                               }
+                       }
+                       // Elide ignored nodes.
+                       if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 {
+                               deferredEllipsis = !(k == reflect.Slice || k == reflect.Array)
+                               if !deferredEllipsis {
+                                       list.AppendEllipsis(diffStats{})
+                               }
+                               continue
+                       }
+                       if out := opts.FormatDiff(r.Value, ptrs); out != nil {
+                               list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+                       }
+               }
+               if deferredEllipsis {
+                       list.AppendEllipsis(diffStats{})
+               }
+               return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+       case diffUnknown:
+       default:
+               panic("invalid diff mode")
+       }
+
+       // Handle differencing.
+       var numDiffs int
+       var list textList
+       var keys []reflect.Value // invariant: len(list) == len(keys)
+       groups := coalesceAdjacentRecords(name, recs)
+       maxGroup := diffStats{Name: name}
+       for i, ds := range groups {
+               if maxLen >= 0 && numDiffs >= maxLen {
+                       maxGroup = maxGroup.Append(ds)
+                       continue
+               }
+
+               // Handle equal records.
+               if ds.NumDiff() == 0 {
+                       // Compute the number of leading and trailing records to print.
+                       var numLo, numHi int
+                       numEqual := ds.NumIgnored + ds.NumIdentical
+                       for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 {
+                               if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
+                                       break
+                               }
+                               numLo++
+                       }
+                       for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 {
+                               if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
+                                       break
+                               }
+                               numHi++
+                       }
+                       if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 {
+                               numHi++ // Avoid pointless coalescing of a single equal record
+                       }
+
+                       // Format the equal values.
+                       for _, r := range recs[:numLo] {
+                               out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
+                               list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+                               keys = append(keys, r.Key)
+                       }
+                       if numEqual > numLo+numHi {
+                               ds.NumIdentical -= numLo + numHi
+                               list.AppendEllipsis(ds)
+                               for len(keys) < len(list) {
+                                       keys = append(keys, reflect.Value{})
+                               }
+                       }
+                       for _, r := range recs[numEqual-numHi : numEqual] {
+                               out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
+                               list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+                               keys = append(keys, r.Key)
+                       }
+                       recs = recs[numEqual:]
+                       continue
+               }
+
+               // Handle unequal records.
+               for _, r := range recs[:ds.NumDiff()] {
+                       switch {
+                       case opts.CanFormatDiffSlice(r.Value):
+                               out := opts.FormatDiffSlice(r.Value)
+                               list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+                               keys = append(keys, r.Key)
+                       case r.Value.NumChildren == r.Value.MaxDepth:
+                               outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
+                               outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
+                               for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
+                                       opts2 := verbosityPreset(opts, i)
+                                       outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
+                                       outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
+                               }
+                               if outx != nil {
+                                       list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
+                                       keys = append(keys, r.Key)
+                               }
+                               if outy != nil {
+                                       list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
+                                       keys = append(keys, r.Key)
+                               }
+                       default:
+                               out := opts.FormatDiff(r.Value, ptrs)
+                               list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+                               keys = append(keys, r.Key)
+                       }
+               }
+               recs = recs[ds.NumDiff():]
+               numDiffs += ds.NumDiff()
+       }
+       if maxGroup.IsZero() {
+               assert(len(recs) == 0)
+       } else {
+               list.AppendEllipsis(maxGroup)
+               for len(keys) < len(list) {
+                       keys = append(keys, reflect.Value{})
+               }
+       }
+       assert(len(list) == len(keys))
+
+       // For maps, the default formatting logic uses fmt.Stringer which may
+       // produce ambiguous output. Avoid calling String to disambiguate.
+       if k == reflect.Map {
+               var ambiguous bool
+               seenKeys := map[string]reflect.Value{}
+               for i, currKey := range keys {
+                       if currKey.IsValid() {
+                               strKey := list[i].Key
+                               prevKey, seen := seenKeys[strKey]
+                               if seen && prevKey.CanInterface() && currKey.CanInterface() {
+                                       ambiguous = prevKey.Interface() != currKey.Interface()
+                                       if ambiguous {
+                                               break
+                                       }
+                               }
+                               seenKeys[strKey] = currKey
+                       }
+               }
+               if ambiguous {
+                       for i, k := range keys {
+                               if k.IsValid() {
+                                       list[i].Key = formatMapKey(k, true, ptrs)
+                               }
+                       }
+               }
+       }
+
+       return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+}
+
+// coalesceAdjacentRecords coalesces the list of records into groups of
+// adjacent equal, or unequal counts.
+func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) {
+       var prevCase int // Arbitrary index into which case last occurred
+       lastStats := func(i int) *diffStats {
+               if prevCase != i {
+                       groups = append(groups, diffStats{Name: name})
+                       prevCase = i
+               }
+               return &groups[len(groups)-1]
+       }
+       for _, r := range recs {
+               switch rv := r.Value; {
+               case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0:
+                       lastStats(1).NumIgnored++
+               case rv.NumDiff == 0:
+                       lastStats(1).NumIdentical++
+               case rv.NumDiff > 0 && !rv.ValueY.IsValid():
+                       lastStats(2).NumRemoved++
+               case rv.NumDiff > 0 && !rv.ValueX.IsValid():
+                       lastStats(2).NumInserted++
+               default:
+                       lastStats(2).NumModified++
+               }
+       }
+       return groups
+}