github.com/puellanivis/breton@v0.2.16/lib/sort/radix.go (about) 1 package sort 2 3 import ( 4 "sort" 5 _ "unsafe" // this is to explicitly signal this file is unsafe. 6 ) 7 8 // RadixTest defines a function that Returns true if the i'th element of the sort.RadixInterface is set 9 type RadixTest func(i int) bool 10 11 // RadixInterface defines the functions necessary for Radix to use a radix sort rather than sort.Sort. 12 type RadixInterface interface { 13 Interface 14 15 // Returns start, and end of radix values to run through for RadixFunc 16 RadixRange() (int, int) 17 RadixFunc(r int) RadixTest 18 } 19 20 // Radix attempts to perform a radix sort on the given argument. 21 // 22 // If the argument does not implement RadixInterface, or is not a builtin basic slice, 23 // but it implements sort.Interface, then sort.Sort will be called on the argument. 24 func Radix(a interface{}) { 25 if a == nil { 26 return 27 } 28 29 switch a := a.(type) { 30 case RadixInterface: 31 radix(a) 32 33 case []uint: 34 radix(UintSlice(a)) 35 case []uint8: 36 radix(Uint8Slice(a)) 37 case []uint16: 38 radix(Uint16Slice(a)) 39 case []uint32: 40 radix(Uint32Slice(a)) 41 case []uint64: 42 radix(Uint64Slice(a)) 43 44 case []int: 45 radix(IntSlice(a)) 46 case []int8: 47 radix(Int8Slice(a)) 48 case []int16: 49 radix(Int16Slice(a)) 50 case []int32: 51 radix(Int32Slice(a)) 52 case []int64: 53 radix(Int64Slice(a)) 54 55 case []float64: 56 radix(Float64Slice(a)) 57 case []float32: 58 radix(Float32Slice(a)) 59 60 case []string: 61 radix(StringSlice(a)) 62 63 default: 64 // fallback: use the builtin sort.Sort 65 sort.Sort(a.(sort.Interface)) 66 } 67 } 68 69 func radix(a RadixInterface) { 70 s, e := a.RadixRange() 71 quickRadix(a, 0, a.Len(), s, e+1) 72 } 73 74 func sortTwo(a RadixInterface, i int) { 75 if a.Less(i+1, i) { 76 a.Swap(i, i+1) 77 } 78 } 79 80 func quickRadix(a RadixInterface, start, end, radix, last int) { 81 r := end - start 82 if r < 3 { 83 if r == 2 { 84 sortTwo(a, start) 85 } 86 return 87 } 88 89 if qsortInstead(r, radix, last) { 90 quickSort(a, start, end, maxDepth(r)) 91 return 92 } 93 94 radixSort(a, start, end, radix, last) 95 } 96 97 type swapFunc func(i, j int) 98 99 func radixPass(f RadixTest, swap swapFunc, start, end int) (pivot int) { 100 i, j := start, end-1 101 102 for i < j { 103 // from the start, find the i-th item that satisfies radix. 104 for i < j && !f(i) { 105 i++ 106 } 107 108 // from the end, find the j-th item that doesn’t satisfy radix. 109 for i < j && f(j) { 110 j-- 111 } 112 113 if j <= i { 114 // avoid swapping if they’ve passed each other, or are the same thing… 115 // while the swap is no big deal, the extra increments not good 116 break 117 } 118 119 swap(i, j) 120 i++ 121 j-- 122 } 123 124 // we’re standing on a pivot, if it doesn’t satisfy pivot, then pivot just after. 125 if i == j && !f(i) { 126 i++ 127 } 128 129 return i 130 } 131 132 func radixSort(a RadixInterface, start, end, radix, last int) { 133 for radix < last { 134 r := end - start 135 if r < 3 { 136 if r == 2 { 137 sortTwo(a, start) 138 } 139 return 140 } 141 142 if qsortInstead(r, radix, last) { 143 quickSort(a, start, end, maxDepth(r)) 144 return 145 } 146 147 pivot := radixPass(a.RadixFunc(radix), a.Swap, start, end) 148 149 radix++ 150 151 if pivot-start < end-pivot { 152 quickRadix(a, start, pivot, radix, last) 153 start = pivot 154 155 } else { 156 quickRadix(a, pivot, end, radix, last) 157 end = pivot 158 } 159 } 160 }