1 // Copyright 2009 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 file.
16 var ints
= [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
17 var float64s
= [...]float64{74.3, 59.0, math
.Inf(1), 238.2, -784.0, 2.3, math
.NaN(), math
.NaN(), math
.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
18 var strings
= [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
20 func TestSortIntSlice(t
*testing
.T
) {
22 a
:= IntSlice(data
[0:])
25 t
.Errorf("sorted %v", ints
)
26 t
.Errorf(" got %v", data
)
30 func TestSortFloat64Slice(t
*testing
.T
) {
32 a
:= Float64Slice(data
[0:])
35 t
.Errorf("sorted %v", float64s
)
36 t
.Errorf(" got %v", data
)
40 func TestSortStringSlice(t
*testing
.T
) {
42 a
:= StringSlice(data
[0:])
45 t
.Errorf("sorted %v", strings
)
46 t
.Errorf(" got %v", data
)
50 func TestInts(t
*testing
.T
) {
53 if !IntsAreSorted(data
[0:]) {
54 t
.Errorf("sorted %v", ints
)
55 t
.Errorf(" got %v", data
)
59 func TestFloat64s(t
*testing
.T
) {
62 if !Float64sAreSorted(data
[0:]) {
63 t
.Errorf("sorted %v", float64s
)
64 t
.Errorf(" got %v", data
)
68 func TestStrings(t
*testing
.T
) {
71 if !StringsAreSorted(data
[0:]) {
72 t
.Errorf("sorted %v", strings
)
73 t
.Errorf(" got %v", data
)
77 func TestSortLarge_Random(t
*testing
.T
) {
82 data
:= make([]int, n
)
83 for i
:= 0; i
< len(data
); i
++ {
84 data
[i
] = rand
.Intn(100)
86 if IntsAreSorted(data
) {
87 t
.Fatalf("terrible rand.rand")
90 if !IntsAreSorted(data
) {
91 t
.Errorf("sort didn't sort - 1M ints")
95 func TestReverseSortIntSlice(t
*testing
.T
) {
98 a
:= IntSlice(data
[0:])
100 r
:= IntSlice(data1
[0:])
102 for i
:= 0; i
< len(data
); i
++ {
103 if a
[i
] != r
[len(data
)-1-i
] {
104 t
.Errorf("reverse sort didn't sort")
112 type nonDeterministicTestingData
struct {
116 func (t
*nonDeterministicTestingData
) Len() int {
119 func (t
*nonDeterministicTestingData
) Less(i
, j
int) bool {
120 if i
< 0 || j
< 0 || i
>= t
.Len() || j
>= t
.Len() {
121 panic("nondeterministic comparison out of bounds")
123 return t
.r
.Float32() < 0.5
125 func (t
*nonDeterministicTestingData
) Swap(i
, j
int) {
126 if i
< 0 || j
< 0 || i
>= t
.Len() || j
>= t
.Len() {
127 panic("nondeterministic comparison out of bounds")
131 func TestNonDeterministicComparison(t
*testing
.T
) {
132 // Ensure that sort.Sort does not panic when Less returns inconsistent results.
133 // See https://golang.org/issue/14377.
135 if r
:= recover(); r
!= nil {
140 td
:= &nonDeterministicTestingData
{
141 r
: rand
.New(rand
.NewSource(0)),
144 for i
:= 0; i
< 10; i
++ {
149 func BenchmarkSortString1K(b
*testing
.B
) {
151 for i
:= 0; i
< b
.N
; i
++ {
152 data
:= make([]string, 1<<10)
153 for i
:= 0; i
< len(data
); i
++ {
154 data
[i
] = strconv
.Itoa(i
^ 0x2cc)
162 func BenchmarkStableString1K(b
*testing
.B
) {
164 for i
:= 0; i
< b
.N
; i
++ {
165 data
:= make([]string, 1<<10)
166 for i
:= 0; i
< len(data
); i
++ {
167 data
[i
] = strconv
.Itoa(i
^ 0x2cc)
170 Stable(StringSlice(data
))
175 func BenchmarkSortInt1K(b
*testing
.B
) {
177 for i
:= 0; i
< b
.N
; i
++ {
178 data
:= make([]int, 1<<10)
179 for i
:= 0; i
< len(data
); i
++ {
188 func BenchmarkStableInt1K(b
*testing
.B
) {
190 for i
:= 0; i
< b
.N
; i
++ {
191 data
:= make([]int, 1<<10)
192 for i
:= 0; i
< len(data
); i
++ {
196 Stable(IntSlice(data
))
201 func BenchmarkSortInt64K(b
*testing
.B
) {
203 for i
:= 0; i
< b
.N
; i
++ {
204 data
:= make([]int, 1<<16)
205 for i
:= 0; i
< len(data
); i
++ {
214 func BenchmarkStableInt64K(b
*testing
.B
) {
216 for i
:= 0; i
< b
.N
; i
++ {
217 data
:= make([]int, 1<<16)
218 for i
:= 0; i
< len(data
); i
++ {
222 Stable(IntSlice(data
))
246 type testingData
struct {
250 maxswap
int // number of swaps allowed
254 func (d
*testingData
) Len() int { return len(d
.data
) }
255 func (d
*testingData
) Less(i
, j
int) bool {
257 return d
.data
[i
] < d
.data
[j
]
259 func (d
*testingData
) Swap(i
, j
int) {
260 if d
.nswap
>= d
.maxswap
{
261 d
.t
.Errorf("%s: used %d swaps sorting slice of %d", d
.desc
, d
.nswap
, len(d
.data
))
265 d
.data
[i
], d
.data
[j
] = d
.data
[j
], d
.data
[i
]
268 func min(a
, b
int) int {
283 func testBentleyMcIlroy(t
*testing
.T
, sort
func(Interface
), maxswap
func(int) int) {
284 sizes
:= []int{100, 1023, 1024, 1025}
286 sizes
= []int{100, 127, 128, 129}
288 dists
:= []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
289 modes
:= []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
290 var tmp1
, tmp2
[1025]int
291 for _
, n
:= range sizes
{
292 for m
:= 1; m
< 2*n
; m
*= 2 {
293 for dist
:= 0; dist
< _NDist
; dist
++ {
297 for i
:= 0; i
< n
; i
++ {
302 data
[i
] = rand
.Intn(m
)
304 data
[i
] = (i
*m
+ i
) % n
308 if rand
.Intn(m
) != 0 {
319 for mode
:= 0; mode
< _NMode
; mode
++ {
322 for i
:= 0; i
< n
; i
++ {
326 for i
:= 0; i
< n
; i
++ {
327 mdata
[i
] = data
[n
-i
-1]
329 case _ReverseFirstHalf
:
330 for i
:= 0; i
< n
/2; i
++ {
331 mdata
[i
] = data
[n
/2-i
-1]
333 for i
:= n
/ 2; i
< n
; i
++ {
336 case _ReverseSecondHalf
:
337 for i
:= 0; i
< n
/2; i
++ {
340 for i
:= n
/ 2; i
< n
; i
++ {
341 mdata
[i
] = data
[n
-(i
-n
/2)-1]
344 for i
:= 0; i
< n
; i
++ {
347 // Ints is known to be correct
348 // because mode Sort runs after mode _Copy.
351 for i
:= 0; i
< n
; i
++ {
352 mdata
[i
] = data
[i
] + i%5
356 desc
:= fmt
.Sprintf("n=%d m=%d dist=%s mode=%s", n
, m
, dists
[dist
], modes
[mode
])
357 d
:= &testingData
{desc
: desc
, t
: t
, data
: mdata
[0:n
], maxswap
: maxswap(n
)}
359 // Uncomment if you are trying to improve the number of compares/swaps.
360 //t.Logf("%s: ncmp=%d, nswp=%d", desc, d.ncmp, d.nswap)
362 // If we were testing C qsort, we'd have to make a copy
363 // of the slice and sort it ourselves and then compare
364 // x against it, to ensure that qsort was only permuting
365 // the data, not (for example) overwriting it with zeros.
367 // In go, we don't have to be so paranoid: since the only
368 // mutating method Sort can call is TestingData.swap,
369 // it suffices here just to check that the final slice is sorted.
370 if !IntsAreSorted(mdata
) {
371 t
.Errorf("%s: ints not sorted", desc
)
372 t
.Errorf("\t%v", mdata
)
381 func TestSortBM(t
*testing
.T
) {
382 testBentleyMcIlroy(t
, Sort
, func(n
int) int { return n
* lg(n
) * 12 / 10 })
385 func TestHeapsortBM(t
*testing
.T
) {
386 testBentleyMcIlroy(t
, Heapsort
, func(n
int) int { return n
* lg(n
) * 12 / 10 })
389 func TestStableBM(t
*testing
.T
) {
390 testBentleyMcIlroy(t
, Stable
, func(n
int) int { return n
* lg(n
) * lg(n
) / 3 })
393 // This is based on the "antiquicksort" implementation by M. Douglas McIlroy.
394 // See http://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info.
395 type adversaryTestingData
struct {
401 func (d
*adversaryTestingData
) Len() int { return len(d
.data
) }
403 func (d
*adversaryTestingData
) Less(i
, j
int) bool {
404 if _
, present
:= d
.keys
[i
]; !present
{
405 if _
, present
:= d
.keys
[j
]; !present
{
406 if i
== d
.candidate
{
407 d
.keys
[i
] = len(d
.keys
)
409 d
.keys
[j
] = len(d
.keys
)
414 if _
, present
:= d
.keys
[i
]; !present
{
418 if _
, present
:= d
.keys
[j
]; !present
{
423 return d
.keys
[i
] >= d
.keys
[j
]
426 func (d
*adversaryTestingData
) Swap(i
, j
int) {
427 d
.data
[i
], d
.data
[j
] = d
.data
[j
], d
.data
[i
]
430 func TestAdversary(t
*testing
.T
) {
432 data
:= make([]int, size
)
433 for i
:= 0; i
< size
; i
++ {
437 d
:= &adversaryTestingData
{data
, make(map[int]int), 0}
438 Sort(d
) // This should degenerate to heapsort.
441 func TestStableInts(t
*testing
.T
) {
443 Stable(IntSlice(data
[0:]))
444 if !IntsAreSorted(data
[0:]) {
445 t
.Errorf("nsorted %v\n got %v", ints
, data
)
449 type intPairs
[]struct {
453 // IntPairs compare on a only.
454 func (d intPairs
) Len() int { return len(d
) }
455 func (d intPairs
) Less(i
, j
int) bool { return d
[i
].a
< d
[j
].a
}
456 func (d intPairs
) Swap(i
, j
int) { d
[i
], d
[j
] = d
[j
], d
[i
] }
458 // Record initial order in B.
459 func (d intPairs
) initB() {
465 // InOrder checks if a-equal elements were not reordered.
466 func (d intPairs
) inOrder() bool {
467 lastA
, lastB
:= -1, 0
468 for i
:= 0; i
< len(d
); i
++ {
482 func TestStability(t
*testing
.T
) {
487 data
:= make(intPairs
, n
)
489 // random distribution
490 for i
:= 0; i
< len(data
); i
++ {
491 data
[i
].a
= rand
.Intn(m
)
494 t
.Fatalf("terrible rand.rand")
499 t
.Errorf("Stable didn't sort %d ints", n
)
502 t
.Errorf("Stable wasn't stable on %d ints", n
)
509 t
.Errorf("Stable shuffled sorted %d ints (order)", n
)
512 t
.Errorf("Stable shuffled sorted %d ints (stability)", n
)
516 for i
:= 0; i
< len(data
); i
++ {
517 data
[i
].a
= len(data
) - i
522 t
.Errorf("Stable didn't sort %d ints", n
)
525 t
.Errorf("Stable wasn't stable on %d ints", n
)
529 var countOpsSizes
= []int{1e2
, 3e2
, 1e3
, 3e3
, 1e4
, 3e4
, 1e5
, 3e5
, 1e6
}
531 func countOps(t
*testing
.T
, algo
func(Interface
), name
string) {
532 sizes
:= countOpsSizes
536 if !testing
.Verbose() {
537 t
.Skip("Counting skipped as non-verbose mode.")
539 for _
, n
:= range sizes
{
543 data
: make([]int, n
),
546 for i
:= 0; i
< n
; i
++ {
547 td
.data
[i
] = rand
.Intn(n
/ 5)
550 t
.Logf("%s %8d elements: %11d Swap, %10d Less", name
, n
, td
.nswap
, td
.ncmp
)
554 func TestCountStableOps(t
*testing
.T
) { countOps(t
, Stable
, "Stable") }
555 func TestCountSortOps(t
*testing
.T
) { countOps(t
, Sort
, "Sort ") }
557 func bench(b
*testing
.B
, size
int, algo
func(Interface
), name
string) {
559 data
:= make(intPairs
, size
)
561 for i
:= 0; i
< b
.N
; i
++ {
562 for n
:= size
- 3; n
<= size
+3; n
++ {
563 for i
:= 0; i
< len(data
); i
++ {
569 data
[i
].a
= int(x
% uint32(n
/5))
576 b
.Errorf("%s did not sort %d ints", name
, n
)
578 if name
== "Stable" && !data
.inOrder() {
579 b
.Errorf("%s unstable on %d ints", name
, n
)
585 func BenchmarkSort1e2(b
*testing
.B
) { bench(b
, 1e2
, Sort
, "Sort") }
586 func BenchmarkStable1e2(b
*testing
.B
) { bench(b
, 1e2
, Stable
, "Stable") }
587 func BenchmarkSort1e4(b
*testing
.B
) { bench(b
, 1e4
, Sort
, "Sort") }
588 func BenchmarkStable1e4(b
*testing
.B
) { bench(b
, 1e4
, Stable
, "Stable") }
589 func BenchmarkSort1e6(b
*testing
.B
) { bench(b
, 1e6
, Sort
, "Sort") }
590 func BenchmarkStable1e6(b
*testing
.B
) { bench(b
, 1e6
, Stable
, "Stable") }