github.com/puellanivis/breton@v0.2.16/lib/sort/sort_test.go (about) 1 package sort 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "sort" 7 "sync" 8 "testing" 9 ) 10 11 func TestInt32s(t *testing.T) { 12 qsortInstead = qsortNever 13 14 l := []int32{42, 5, 7, 2, 3} 15 16 if Int32sAreSorted(l) { 17 t.Error("unsorted int32 list reports as sorted") 18 } 19 20 Int32s(l) 21 22 if !Int32sAreSorted(l) { 23 t.Error("after sorting int32 list reports as not sorted") 24 t.Error("Got:", l) 25 } 26 27 if SearchInt32s(l, 42) != 4 { 28 t.Error("binary search failed for int32 list") 29 } 30 } 31 32 func TestReverseInt32s(t *testing.T) { 33 qsortInstead = qsortNever 34 35 a := []int32{42, 5, 7, 2, 3} 36 l := Reverse(a) 37 38 if IsSorted(l) { 39 t.Error("unsorted reverse int32 list reports as sorted") 40 } 41 42 Sort(l) 43 44 if !IsSorted(l) { 45 t.Error("after reverse sorting int32 list reports as not sorted") 46 t.Error("Got:", l) 47 } 48 49 if got := SearchFor(l, int32(42)); got != 0 { 50 t.Errorf("binary search failed for reversed int32 list got %d wanted 0", got) 51 } 52 } 53 54 func TestInt64s(t *testing.T) { 55 qsortInstead = qsortNever 56 57 l := []int64{42, 5, 7, 2, 3} 58 59 if Int64sAreSorted(l) { 60 t.Error("unsorted int64 list reports as sorted") 61 } 62 63 Sort(l) 64 65 if !Int64sAreSorted(l) { 66 t.Error("after sorting int64 list reports as not sorted") 67 t.Error("Got:", l) 68 } 69 70 if SearchInt64s(l, 42) != 4 { 71 t.Error("binary search failed for int64 list") 72 } 73 } 74 75 var benchIntArray = make([][]int, 5) 76 var benchIntOnce = make([]sync.Once, len(benchIntArray)) 77 78 const ( 79 //benchSize = 1000 80 benchSize = 10000000 81 ) 82 83 func initIntBench(n int) { 84 // bit width here is set to ceil(log_2(benchSize)) - n 85 // With a larger bit width, there will be more recursions based on radi than for quicksort (i.e. log n). 86 // So, the “intelligent” Radix implementation will often switch to using sort.qsort. 87 // 88 // Quick rundown of pure radix, vs “intelligent” Radix, and sort.Sort: 89 // n < 1: pure radix sort is slower; “intelligent” Radix will almost always pick sort.qsort. 90 // n > 3: pure radix sort is faster; “intelligent” Radix will almost never pick sort.qsort. 91 // n = 2: all three run in around the same, and picking one or the other is a wash. 92 // otherwise: “intelligent” Radix will either pick sort.qsort too much or not enough, 93 // so, results end up super non-deterministic, but either n = 1 sucks, or n = 3 does. 94 log := (maxDepth(benchSize) / 2) - n 95 width := log/8 + 1 96 mask := byte(0xff) >> (uint(8 - (log % 8))) 97 if width < 2 { 98 width = 2 99 } 100 fmt.Printf("using a slice of len %d\n", benchSize) 101 fmt.Printf("n = %d is using %d bits << %d\n", n, log, uintMSB-log) 102 b := make([]byte, width) 103 104 for i := 0; i < benchSize; i++ { 105 _, err := rand.Read(b) 106 if err != nil { 107 panic(err) 108 } 109 110 val := int(b[0] & mask) 111 112 for j := 1; j < len(b); j++ { 113 val <<= 8 114 val |= int(b[j]) 115 } 116 117 /* if b[0] & 0x80 != 0 { 118 val = -val 119 } //*/ 120 121 benchIntArray[n] = append(benchIntArray[n], (val<<uint(uintMSB-log))|0x10) 122 } 123 } 124 125 func benchmarkIntAllRadixSort(b *testing.B, n int) { 126 b.StopTimer() 127 benchIntOnce[n].Do(func() { initIntBench(n) }) 128 129 qsortInstead = qsortNever 130 131 buf := make([]int, len(benchIntArray[n])) 132 133 for i := 0; i < b.N; i++ { 134 copy(buf, benchIntArray[n]) 135 136 b.StartTimer() 137 Ints(buf) 138 b.StopTimer() 139 140 if !IntsAreSorted(buf) { 141 b.Fatal("sorting failed!") 142 } 143 } 144 } 145 146 func BenchmarkIntAllRadixSort0(b *testing.B) { 147 benchmarkIntAllRadixSort(b, 0) 148 } 149 func BenchmarkIntAllRadixSort1(b *testing.B) { 150 benchmarkIntAllRadixSort(b, 1) 151 } 152 func BenchmarkIntAllRadixSort2(b *testing.B) { 153 benchmarkIntAllRadixSort(b, 2) 154 } 155 func BenchmarkIntAllRadixSort3(b *testing.B) { 156 benchmarkIntAllRadixSort(b, 3) 157 } 158 func BenchmarkIntAllRadixSort4(b *testing.B) { 159 benchmarkIntAllRadixSort(b, 4) 160 } 161 162 func benchmarkIntRadixSort(b *testing.B, n int) { 163 b.StopTimer() 164 benchIntOnce[n].Do(func() { initIntBench(n) }) 165 166 qsortInstead = qsortSometimes 167 168 buf := make([]int, len(benchIntArray[n])) 169 170 for i := 0; i < b.N; i++ { 171 copy(buf, benchIntArray[n]) 172 173 b.StartTimer() 174 Ints(buf) 175 b.StopTimer() 176 177 if !IntsAreSorted(buf) { 178 b.Fatal("sorting failed!") 179 } 180 } 181 } 182 183 func BenchmarkIntRadixSort0(b *testing.B) { 184 benchmarkIntRadixSort(b, 0) 185 } 186 func BenchmarkIntRadixSort1(b *testing.B) { 187 benchmarkIntRadixSort(b, 1) 188 } 189 func BenchmarkIntRadixSort2(b *testing.B) { 190 benchmarkIntRadixSort(b, 2) 191 } 192 func BenchmarkIntRadixSort3(b *testing.B) { 193 benchmarkIntRadixSort(b, 3) 194 } 195 func BenchmarkIntRadixSort4(b *testing.B) { 196 benchmarkIntRadixSort(b, 4) 197 } 198 199 func benchmarkIntOriginalSort(b *testing.B, n int) { 200 b.StopTimer() 201 benchIntOnce[n].Do(func() { initIntBench(n) }) 202 203 buf := make(IntSlice, len(benchIntArray[n])) 204 205 for i := 0; i < b.N; i++ { 206 copy(buf, benchIntArray[n]) 207 208 b.StartTimer() 209 sort.Sort(buf) 210 b.StopTimer() 211 212 if !IntsAreSorted(buf) { 213 b.Fatal("sorting failed!") 214 } 215 } 216 } 217 218 func BenchmarkIntOriginalSort0(b *testing.B) { 219 benchmarkIntOriginalSort(b, 0) 220 } 221 func BenchmarkIntOriginalSort1(b *testing.B) { 222 benchmarkIntOriginalSort(b, 1) 223 } 224 func BenchmarkIntOriginalSort2(b *testing.B) { 225 benchmarkIntOriginalSort(b, 2) 226 } 227 func BenchmarkIntOriginalSort3(b *testing.B) { 228 benchmarkIntOriginalSort(b, 3) 229 } 230 func BenchmarkIntOriginalSort4(b *testing.B) { 231 benchmarkIntOriginalSort(b, 4) 232 }