Skip to content

Commit

Permalink
Reorganize the new map key sorting functionality.
Browse files Browse the repository at this point in the history
This commit moves the new code related to sorting reflect.Value items into
common.go since it is accessed by both the formatter and the dumper.  It
also adds comments to the new functions and unexports SortValues since it
should be an internal function only.
  • Loading branch information
davecgh committed Nov 15, 2013
1 parent f0ba95e commit de6d1a2
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 43 deletions.
49 changes: 49 additions & 0 deletions spew/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"io"
"reflect"
"sort"
"strconv"
"unsafe"
)
Expand Down Expand Up @@ -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})
}
43 changes: 1 addition & 42 deletions spew/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"os"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion spew/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions spew/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

0 comments on commit de6d1a2

Please sign in to comment.