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

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: 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 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 // cmpForType returns a cmpFn which sorts the data for some type t in the same
353 // order that a go-native map key is compared for equality.
354 func cmpForType(t reflect.Type) cmpFn {
355 switch t.Kind() {
356 case reflect.String:
357 return func(av, bv reflect.Value) int {
358 a, b := av.String(), bv.String()
359 if a < b {
360 return -1
361 } else if a > b {
362 return 1
363 }
364 return 0
365 }
366
367 case reflect.Bool:
368 return func(av, bv reflect.Value) int {
369 a, b := av.Bool(), bv.Bool()
370 if !a && b {
371 return -1
372 } else if a && !b {
373 return 1
374 }
375 return 0
376 }
377
378 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64:
379 return func(av, bv reflect.Value) int {
380 a, b := av.Int(), bv.Int()
381 if a < b {
382 return -1
383 } else if a > b {
384 return 1
385 }
386 return 0
387 }
388
389 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
390 reflect.Uint64, reflect.Uintptr, reflect.UnsafePointer:
391 return func(av, bv reflect.Value) int {
392 a, b := av.Uint(), bv.Uint()
393 if a < b {
394 return -1
395 } else if a > b {
396 return 1
397 }
398 return 0
399 }
400
401 case reflect.Float32, reflect.Float64:
402 return func(av, bv reflect.Value) int {
403 a, b := av.Float(), bv.Float()
404 if a < b {
405 return -1
406 } else if a > b {
407 return 1
408 }
409 return 0
410 }
411
412 case reflect.Interface:
413 return func(av, bv reflect.Value) int {
414 a, b := av.InterfaceData(), bv.InterfaceData()
415 if a[0] < b[0] {
416 return -1
417 } else if a[0] > b[0] {
418 return 1
419 }
420 if a[1] < b[1] {
421 return -1
422 } else if a[1] > b[1] {
423 return 1
424 }
425 return 0
426 }
427
428 case reflect.Complex64, reflect.Complex128:
429 return func(av, bv reflect.Value) int {
430 a, b := av.Complex(), bv.Complex()
431 if real(a) < real(b) {
432 return -1
433 } else if real(a) > real(b) {
434 return 1
435 }
436 if imag(a) < imag(b) {
437 return -1
438 } else if imag(a) > imag(b) {
439 return 1
440 }
441 return 0
442 }
443
444 case reflect.Ptr, reflect.Chan:
445 return func(av, bv reflect.Value) int {
446 a, b := av.Pointer(), bv.Pointer()
447 if a < b {
448 return -1
449 } else if a > b {
450 return 1
451 }
452 return 0
453 }
454
455 case reflect.Struct:
456 cmpLst := make([]cmpFn, t.NumField())
457 for i := range cmpLst {
458 cmpLst[i] = cmpForType(t.Field(i).Type)
459 }
460 return func(a, b reflect.Value) int {
461 for i, cmp := range cmpLst {
462 if rslt := cmp(a.Field(i), b.Field(i)); rslt != 0 {
463 return rslt
464 }
465 }
466 return 0
467 }
468 }
469
470 return nil
471 }
472
359 func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) { 473 func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) {
360 » // Try our stock sortable values. 474 » if cmp := cmpForType(mt.Key()); cmp != nil {
361 » switch mt.Key().Kind() { 475 » » 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 } 476 }
369 } 477 }
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