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

Side by Side 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: 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 unified diff | Download patch
« no previous file with comments | « no previous file | render/render_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package render 5 package render
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "reflect" 10 "reflect"
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 323
324 default: 324 default:
325 buf.WriteString(t.String()) 325 buf.WriteString(t.String())
326 } 326 }
327 327
328 if parens { 328 if parens {
329 buf.WriteRune(')') 329 buf.WriteRune(')')
330 } 330 }
331 } 331 }
332 332
333 type cmpFn func(a, b reflect.Value) int
334
333 type sortableValueSlice struct { 335 type sortableValueSlice struct {
334 » kind reflect.Kind 336 » cmp cmpFn
335 elements []reflect.Value 337 elements []reflect.Value
336 } 338 }
337 339
338 func (s *sortableValueSlice) Len() int { 340 func (s sortableValueSlice) Len() int {
339 return len(s.elements) 341 return len(s.elements)
340 } 342 }
341 343
342 func (s *sortableValueSlice) Less(i, j int) bool { 344 func (s sortableValueSlice) Less(i, j int) bool {
343 » switch s.kind { 345 » return s.cmp(s.elements[i], s.elements[j]) < 0
344 » case reflect.String:
345 » » return s.elements[i].String() < s.elements[j].String()
346
347 » case reflect.Int:
348 » » return s.elements[i].Int() < s.elements[j].Int()
349
350 » default:
351 » » panic(fmt.Errorf("unsupported sort kind: %s", s.kind))
352 » }
353 } 346 }
354 347
355 func (s *sortableValueSlice) Swap(i, j int) { 348 func (s sortableValueSlice) Swap(i, j int) {
356 s.elements[i], s.elements[j] = s.elements[j], s.elements[i] 349 s.elements[i], s.elements[j] = s.elements[j], s.elements[i]
357 } 350 }
358 351
352 func cmpForType(t reflect.Type) cmpFn {
dnj 2016/02/19 19:31:10 nit: document that this specifically aims to opera
iannucci 2016/02/19 21:18:28 Done.
353 switch t.Kind() {
354 case reflect.String:
355 return func(av, bv reflect.Value) int {
356 a, b := av.String(), bv.String()
357 if a < b {
358 return -1
359 } else if a > b {
360 return 1
361 }
362 return 0
363 }
364
365 case reflect.Bool:
366 return func(av, bv reflect.Value) int {
367 a, b := av.Bool(), bv.Bool()
368 if !a && b {
369 return -1
370 } else if a && !b {
371 return 1
372 }
373 return 0
374 }
375
376 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64:
377 return func(av, bv reflect.Value) int {
378 a, b := av.Int(), bv.Int()
379 if a < b {
380 return -1
381 } else if a > b {
382 return 1
383 }
384 return 0
385 }
386
387 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
388 reflect.Uint64, reflect.Uintptr, reflect.UnsafePointer:
389 return func(av, bv reflect.Value) int {
390 a, b := av.Uint(), bv.Uint()
391 if a < b {
392 return -1
393 } else if a > b {
394 return 1
395 }
396 return 0
397 }
398
399 case reflect.Float32, reflect.Float64:
400 return func(av, bv reflect.Value) int {
401 a, b := av.Float(), bv.Float()
402 if a < b {
403 return -1
404 } else if a > b {
405 return 1
406 }
407 return 0
408 }
409
410 case reflect.Interface:
411 return func(av, bv reflect.Value) int {
412 a, b := av.InterfaceData(), bv.InterfaceData()
413 if a[0] < b[0] {
414 return -1
415 } else if a[0] > b[0] {
416 return 1
417 }
418 if a[1] < b[1] {
419 return -1
420 } else if a[1] > b[1] {
421 return 1
422 }
423 return 0
424 }
425
426 case reflect.Complex64, reflect.Complex128:
427 return func(av, bv reflect.Value) int {
428 a, b := av.Complex(), bv.Complex()
429 if real(a) < real(b) {
430 return -1
431 } else if real(a) > real(b) {
432 return 1
433 }
434 if imag(a) < imag(b) {
435 return -1
436 } else if imag(a) > imag(b) {
437 return 1
438 }
439 return 0
440 }
441
442 case reflect.Ptr, reflect.Chan:
443 return func(av, bv reflect.Value) int {
444 a, b := av.Pointer(), bv.Pointer()
445 if a < b {
446 return -1
447 } else if a > b {
448 return 1
449 }
450 return 0
451 }
452
453 case reflect.Struct:
454 cmpLst := make([]cmpFn, t.NumField())
455 for i := range cmpLst {
456 cmpLst[i] = cmpForType(t.Field(i).Type)
457 }
458 return func(a, b reflect.Value) int {
459 for i, cmp := range cmpLst {
460 rslt := cmp(a.Field(i), b.Field(i))
dnj 2016/02/19 19:31:10 nit: if rstl := cmp(); rstl != 0 { ... }
iannucci 2016/02/19 21:18:28 Done.
461 if rslt != 0 {
462 return rslt
463 }
464 }
465 return 0
466 }
467 }
468
469 return nil
470 }
471
359 func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) { 472 func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) {
360 » // Try our stock sortable values. 473 » if cmp := cmpForType(mt.Key()); cmp != nil {
361 » switch mt.Key().Kind() { 474 » » sort.Sort(sortableValueSlice{cmp, k})
362 » case reflect.String, reflect.Int:
363 » » vs := &sortableValueSlice{
364 » » » kind: mt.Key().Kind(),
365 » » » elements: k,
366 » » }
367 » » sort.Sort(vs)
368 } 475 }
369 } 476 }
OLDNEW
« 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