diff options
Diffstat (limited to 'spew/common.go')
| -rw-r--r-- | spew/common.go | 75 |
1 files changed, 68 insertions, 7 deletions
diff --git a/spew/common.go b/spew/common.go index 81fac0b..8252cd3 100644 --- a/spew/common.go +++ b/spew/common.go @@ -17,6 +17,7 @@ package spew import ( + "bytes" "fmt" "io" "reflect" @@ -325,7 +326,61 @@ func printHexPtr(w io.Writer, p uintptr) { // valuesSorter implements sort.Interface to allow a slice of reflect.Value // elements to be sorted. type valuesSorter struct { - values []reflect.Value + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false } // Len returns the number of values in the slice. It is part of the @@ -338,6 +393,9 @@ func (s *valuesSorter) Len() int { // sort.Interface implementation. func (s *valuesSorter) Swap(i, j int) { s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } } // valueSortLess returns whether the first value should sort before the second @@ -375,15 +433,18 @@ func valueSortLess(a, b reflect.Value) bool { // Less returns whether the value at index i should sort before the // value at index j. It is part of the sort.Interface implementation. func (s *valuesSorter) Less(i, j int) bool { - return valueSortLess(s.values[i], s.values[j]) + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] } -// sortValues is a generic sort function for native types: int, uint, bool, -// string and uintptr. Other inputs are sorted according to their -// Value.String() value to ensure display stability. -func sortValues(values []reflect.Value) { +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { if len(values) == 0 { return } - sort.Sort(&valuesSorter{values}) + sort.Sort(newValuesSorter(values, cs)) } |
