github.com/marinho/drone@v0.2.1-0.20140504195434-d3ba962e89a7/Godeps/_workspace/src/launchpad.net/goyaml/sorter.go (about) 1 package goyaml 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 ar, br := []rune(a.String()), []rune(b.String()) 40 for i := 0; i < len(ar) && i < len(br); i++ { 41 if ar[i] == br[i] { 42 continue 43 } 44 al := unicode.IsLetter(ar[i]) 45 bl := unicode.IsLetter(br[i]) 46 if al && bl { 47 return ar[i] < br[i] 48 } 49 if al || bl { 50 return bl 51 } 52 var ai, bi int 53 var an, bn int64 54 for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 55 an = an*10 + int64(ar[ai]-'0') 56 } 57 for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 58 bn = bn*10 + int64(br[bi]-'0') 59 } 60 if an != bn { 61 return an < bn 62 } 63 if ai != bi { 64 return ai < bi 65 } 66 return ar[i] < br[i] 67 } 68 return len(ar) < len(br) 69 } 70 71 // keyFloat returns a float value for v if it is a number/bool 72 // and whether it is a number/bool or not. 73 func keyFloat(v reflect.Value) (f float64, ok bool) { 74 switch v.Kind() { 75 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 76 return float64(v.Int()), true 77 case reflect.Float32, reflect.Float64: 78 return v.Float(), true 79 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 80 return float64(v.Uint()), true 81 case reflect.Bool: 82 if v.Bool() { 83 return 1, true 84 } 85 return 0, true 86 } 87 return 0, false 88 } 89 90 // numLess returns whether a < b. 91 // a and b must necessarily have the same kind. 92 func numLess(a, b reflect.Value) bool { 93 switch a.Kind() { 94 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 95 return a.Int() < b.Int() 96 case reflect.Float32, reflect.Float64: 97 return a.Float() < b.Float() 98 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 99 return a.Uint() < b.Uint() 100 case reflect.Bool: 101 return !a.Bool() && b.Bool() 102 } 103 panic("not a number") 104 }