You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

105 lines
2.9 KiB

  1. // Copyright 2017, The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE.md file.
  4. package value
  5. import (
  6. "fmt"
  7. "math"
  8. "reflect"
  9. "sort"
  10. )
  11. // SortKeys sorts a list of map keys, deduplicating keys if necessary.
  12. // The type of each value must be comparable.
  13. func SortKeys(vs []reflect.Value) []reflect.Value {
  14. if len(vs) == 0 {
  15. return vs
  16. }
  17. // Sort the map keys.
  18. sort.Slice(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) })
  19. // Deduplicate keys (fails for NaNs).
  20. vs2 := vs[:1]
  21. for _, v := range vs[1:] {
  22. if isLess(vs2[len(vs2)-1], v) {
  23. vs2 = append(vs2, v)
  24. }
  25. }
  26. return vs2
  27. }
  28. // isLess is a generic function for sorting arbitrary map keys.
  29. // The inputs must be of the same type and must be comparable.
  30. func isLess(x, y reflect.Value) bool {
  31. switch x.Type().Kind() {
  32. case reflect.Bool:
  33. return !x.Bool() && y.Bool()
  34. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  35. return x.Int() < y.Int()
  36. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  37. return x.Uint() < y.Uint()
  38. case reflect.Float32, reflect.Float64:
  39. fx, fy := x.Float(), y.Float()
  40. return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy)
  41. case reflect.Complex64, reflect.Complex128:
  42. cx, cy := x.Complex(), y.Complex()
  43. rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy)
  44. if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) {
  45. return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy)
  46. }
  47. return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry)
  48. case reflect.Ptr, reflect.UnsafePointer, reflect.Chan:
  49. return x.Pointer() < y.Pointer()
  50. case reflect.String:
  51. return x.String() < y.String()
  52. case reflect.Array:
  53. for i := 0; i < x.Len(); i++ {
  54. if isLess(x.Index(i), y.Index(i)) {
  55. return true
  56. }
  57. if isLess(y.Index(i), x.Index(i)) {
  58. return false
  59. }
  60. }
  61. return false
  62. case reflect.Struct:
  63. for i := 0; i < x.NumField(); i++ {
  64. if isLess(x.Field(i), y.Field(i)) {
  65. return true
  66. }
  67. if isLess(y.Field(i), x.Field(i)) {
  68. return false
  69. }
  70. }
  71. return false
  72. case reflect.Interface:
  73. vx, vy := x.Elem(), y.Elem()
  74. if !vx.IsValid() || !vy.IsValid() {
  75. return !vx.IsValid() && vy.IsValid()
  76. }
  77. tx, ty := vx.Type(), vy.Type()
  78. if tx == ty {
  79. return isLess(x.Elem(), y.Elem())
  80. }
  81. if tx.Kind() != ty.Kind() {
  82. return vx.Kind() < vy.Kind()
  83. }
  84. if tx.String() != ty.String() {
  85. return tx.String() < ty.String()
  86. }
  87. if tx.PkgPath() != ty.PkgPath() {
  88. return tx.PkgPath() < ty.PkgPath()
  89. }
  90. // This can happen in rare situations, so we fallback to just comparing
  91. // the unique pointer for a reflect.Type. This guarantees deterministic
  92. // ordering within a program, but it is obviously not stable.
  93. return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer()
  94. default:
  95. // Must be Func, Map, or Slice; which are not comparable.
  96. panic(fmt.Sprintf("%T is not comparable", x.Type()))
  97. }
  98. }