github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/encoding/kmgYaml/sorter.go (about) 1 package kmgYaml 2 3 import ( 4 "reflect" 5 //"unicode" 6 ) 7 8 type keyList []reflect.Value 9 10 func (l keyList) Len() int { return len(l) } 11 func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 func (l keyList) Less(i, j int) bool { 13 a := l[i] 14 b := l[j] 15 ak := a.Kind() 16 bk := b.Kind() 17 for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 a = a.Elem() 19 ak = a.Kind() 20 } 21 for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 b = b.Elem() 23 bk = b.Kind() 24 } 25 af, aok := keyFloat(a) 26 bf, bok := keyFloat(b) 27 if aok && bok { 28 if af != bf { 29 return af < bf 30 } 31 if ak != bk { 32 return ak < bk 33 } 34 return numLess(a, b) 35 } 36 if ak != reflect.String || bk != reflect.String { 37 return ak < bk 38 } 39 return a.String() < b.String() 40 /* 41 too complex stuff and lots of bugs, just compare string by bytes. 42 ar, br := []rune(a.String()), []rune(b.String()) 43 for i := 0; i < len(ar) && i < len(br); i++ { 44 if ar[i] == br[i] { 45 continue 46 } 47 al := unicode.IsLetter(ar[i]) 48 bl := unicode.IsLetter(br[i]) 49 if al && bl { 50 return ar[i] < br[i] 51 } 52 if al || bl { 53 return bl 54 } 55 var ai, bi int 56 var an, bn int64 57 for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 58 an = an*10 + int64(ar[ai]-'0') 59 } 60 for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 61 bn = bn*10 + int64(br[bi]-'0') 62 } 63 if an != bn { 64 return an < bn 65 } 66 if ai != bi { 67 return ai < bi 68 } 69 return ar[i] < br[i] 70 } 71 return len(ar) < len(br) 72 */ 73 } 74 75 // keyFloat returns a float value for v if it is a number/bool 76 // and whether it is a number/bool or not. 77 func keyFloat(v reflect.Value) (f float64, ok bool) { 78 switch v.Kind() { 79 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 80 return float64(v.Int()), true 81 case reflect.Float32, reflect.Float64: 82 return v.Float(), true 83 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 84 return float64(v.Uint()), true 85 case reflect.Bool: 86 if v.Bool() { 87 return 1, true 88 } 89 return 0, true 90 } 91 return 0, false 92 } 93 94 // numLess returns whether a < b. 95 // a and b must necessarily have the same kind. 96 func numLess(a, b reflect.Value) bool { 97 switch a.Kind() { 98 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 99 return a.Int() < b.Int() 100 case reflect.Float32, reflect.Float64: 101 return a.Float() < b.Float() 102 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 103 return a.Uint() < b.Uint() 104 case reflect.Bool: 105 return !a.Bool() && b.Bool() 106 } 107 panic("not a number") 108 }