Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1264)

Unified Diff: render/render.go

Issue 1716443004: Deterministic sorting for all map key types. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/go-render.git@implicit_render
Patch Set: fix nits Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | render/render_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: render/render.go
diff --git a/render/render.go b/render/render.go
index bdb307ce9d49be5f2662606dbe61c7e6485edea8..23b7a586761fcb6e7e077be62ce767f3b3ef9483 100644
--- a/render/render.go
+++ b/render/render.go
@@ -330,40 +330,148 @@ func writeType(buf *bytes.Buffer, ptrs int, t reflect.Type) {
}
}
+type cmpFn func(a, b reflect.Value) int
+
type sortableValueSlice struct {
- kind reflect.Kind
+ cmp cmpFn
elements []reflect.Value
}
-func (s *sortableValueSlice) Len() int {
+func (s sortableValueSlice) Len() int {
return len(s.elements)
}
-func (s *sortableValueSlice) Less(i, j int) bool {
- switch s.kind {
+func (s sortableValueSlice) Less(i, j int) bool {
+ return s.cmp(s.elements[i], s.elements[j]) < 0
+}
+
+func (s sortableValueSlice) Swap(i, j int) {
+ s.elements[i], s.elements[j] = s.elements[j], s.elements[i]
+}
+
+// cmpForType returns a cmpFn which sorts the data for some type t in the same
+// order that a go-native map key is compared for equality.
+func cmpForType(t reflect.Type) cmpFn {
+ switch t.Kind() {
case reflect.String:
- return s.elements[i].String() < s.elements[j].String()
+ return func(av, bv reflect.Value) int {
+ a, b := av.String(), bv.String()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
- case reflect.Int:
- return s.elements[i].Int() < s.elements[j].Int()
+ case reflect.Bool:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Bool(), bv.Bool()
+ if !a && b {
+ return -1
+ } else if a && !b {
+ return 1
+ }
+ return 0
+ }
- default:
- panic(fmt.Errorf("unsupported sort kind: %s", s.kind))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Int(), bv.Int()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64, reflect.Uintptr, reflect.UnsafePointer:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Uint(), bv.Uint()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Float32, reflect.Float64:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Float(), bv.Float()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Interface:
+ return func(av, bv reflect.Value) int {
+ a, b := av.InterfaceData(), bv.InterfaceData()
+ if a[0] < b[0] {
+ return -1
+ } else if a[0] > b[0] {
+ return 1
+ }
+ if a[1] < b[1] {
+ return -1
+ } else if a[1] > b[1] {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Complex64, reflect.Complex128:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Complex(), bv.Complex()
+ if real(a) < real(b) {
+ return -1
+ } else if real(a) > real(b) {
+ return 1
+ }
+ if imag(a) < imag(b) {
+ return -1
+ } else if imag(a) > imag(b) {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Ptr, reflect.Chan:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Pointer(), bv.Pointer()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Struct:
+ cmpLst := make([]cmpFn, t.NumField())
+ for i := range cmpLst {
+ cmpLst[i] = cmpForType(t.Field(i).Type)
+ }
+ return func(a, b reflect.Value) int {
+ for i, cmp := range cmpLst {
+ if rslt := cmp(a.Field(i), b.Field(i)); rslt != 0 {
+ return rslt
+ }
+ }
+ return 0
+ }
}
-}
-func (s *sortableValueSlice) Swap(i, j int) {
- s.elements[i], s.elements[j] = s.elements[j], s.elements[i]
+ return nil
}
func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) {
- // Try our stock sortable values.
- switch mt.Key().Kind() {
- case reflect.String, reflect.Int:
- vs := &sortableValueSlice{
- kind: mt.Key().Kind(),
- elements: k,
- }
- sort.Sort(vs)
+ if cmp := cmpForType(mt.Key()); cmp != nil {
+ sort.Sort(sortableValueSlice{cmp, k})
}
}
« no previous file with comments | « no previous file | render/render_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698