diff --git a/spew/common.go b/spew/common.go index 11b6d56..3a3a2b0 100644 --- a/spew/common.go +++ b/spew/common.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "reflect" + "sort" "strconv" "unsafe" ) @@ -249,3 +250,51 @@ func printHexPtr(w io.Writer, p uintptr) { buf = buf[i:] w.Write(buf) } + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] +} + +// 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 { + switch s.values[i].Kind() { + case reflect.Bool: + return !s.values[i].Bool() && s.values[j].Bool() + case reflect.Float32, reflect.Float64: + return s.values[i].Float() < s.values[j].Float() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return s.values[i].Int() < s.values[j].Int() + case reflect.String: + return s.values[i].String() < s.values[j].String() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return s.values[i].Uint() < s.values[j].Uint() + case reflect.Uintptr: + return s.values[i].UnsafeAddr() < s.values[j].UnsafeAddr() + } + return s.values[i].String() < s.values[j].String() +} + +// 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) { + if len(values) == 0 { + return + } + sort.Sort(&valuesSorter{values}) +} diff --git a/spew/dump.go b/spew/dump.go index b5dcfb2..3d57306 100644 --- a/spew/dump.go +++ b/spew/dump.go @@ -24,7 +24,6 @@ import ( "os" "reflect" "regexp" - "sort" "strconv" "strings" ) @@ -242,46 +241,6 @@ func (d *dumpState) dumpSlice(v reflect.Value) { } } -type valuesSorter struct { - values []reflect.Value -} - -func (s *valuesSorter) Len() int { - return len(s.values) -} - -func (s *valuesSorter) Swap(i, j int) { - s.values[i], s.values[j] = s.values[j], s.values[i] -} - -func (s *valuesSorter) Less(i, j int) bool { - switch s.values[i].Kind() { - case reflect.Bool: - return !s.values[i].Bool() && s.values[j].Bool() - case reflect.Float32, reflect.Float64: - return s.values[i].Float() < s.values[j].Float() - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return s.values[i].Int() < s.values[j].Int() - case reflect.String: - return s.values[i].String() < s.values[j].String() - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return s.values[i].Uint() < s.values[j].Uint() - case reflect.Uintptr: - return s.values[i].UnsafeAddr() < s.values[j].UnsafeAddr() - } - return s.values[i].String() < s.values[j].String() -} - -// 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) { - if len(values) == 0 { - return - } - sort.Sort(&valuesSorter{values}) -} - // dump is the main workhorse for dumping a value. It uses the passed reflect // value to figure out what kind of object we are dealing with and formats it // appropriately. It is a recursive function, however circular data structures @@ -391,7 +350,7 @@ func (d *dumpState) dump(v reflect.Value) { numEntries := v.Len() keys := v.MapKeys() if d.cs.SortKeys { - SortValues(keys) + sortValues(keys) } for i, key := range keys { d.dump(d.unpackValue(key)) diff --git a/spew/format.go b/spew/format.go index fc57fda..b6b1fb0 100644 --- a/spew/format.go +++ b/spew/format.go @@ -303,7 +303,7 @@ func (f *formatState) format(v reflect.Value) { } else { keys := v.MapKeys() if f.cs.SortKeys { - SortValues(keys) + sortValues(keys) } for i, key := range keys { if i > 0 { diff --git a/spew/internal_test.go b/spew/internal_test.go index 05bab97..d8c9761 100644 --- a/spew/internal_test.go +++ b/spew/internal_test.go @@ -155,3 +155,9 @@ func TestAddedReflectValue(t *testing.T) { t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want) } } + +// SortValues makes the internal sortValues function available to the test +// package. +func SortValues(values []reflect.Value) { + sortValues(values) +}