github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/sort/sort_test.gno (about)

     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.
     4  
     5  package sort_test
     6  
     7  import (
     8  	"fmt"
     9  	"math/rand"
    10  	"sort"
    11  	"strconv"
    12  	"testing"
    13  )
    14  
    15  var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
    16  
    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", "%*&^*&^&", "***"}
    19  
    20  /*a XXX removed slice due to reflect methods
    21  func TestSortIntSlice(t *testing.T) {
    22  	data := ints
    23  	a := IntSlice(data[0:])
    24  	Sort(a)
    25  	if !IsSorted(a) {
    26  		t.Errorf("sorted %v", ints)
    27  		t.Errorf("   got %v", data)
    28  	}
    29  }
    30  
    31  func TestSortFloat64Slice(t *testing.T) {
    32  	data := float64s
    33  	a := Float64Slice(data[0:])
    34  	Sort(a)
    35  	if !IsSorted(a) {
    36  		t.Errorf("sorted %v", float64s)
    37  		t.Errorf("   got %v", data)
    38  	}
    39  }
    40  
    41  func TestSortStringSlice(t *testing.T) {
    42  	data := strings
    43  	a := StringSlice(data[0:])
    44  	Sort(a)
    45  	if !IsSorted(a) {
    46  		t.Errorf("sorted %v", strings)
    47  		t.Errorf("   got %v", data)
    48  	}
    49  }
    50  */
    51  
    52  func TestInts(t *testing.T) {
    53  	data := ints
    54  	sort.Ints(data[0:])
    55  	if !sort.IntsAreSorted(data[0:]) {
    56  		t.Errorf("sorted %v", ints)
    57  		t.Errorf("   got %v", data)
    58  	}
    59  }
    60  
    61  /* removed due to float
    62  func TestFloat64s(t *testing.T) {
    63  	data := float64s
    64  	Float64s(data[0:])
    65  	if !Float64sAreSorted(data[0:]) {
    66  		t.Errorf("sorted %v", float64s)
    67  		t.Errorf("   got %v", data)
    68  	}
    69  }
    70  */
    71  
    72  func TestStrings(t *testing.T) {
    73  	data := strings
    74  	sort.Strings(data[0:])
    75  	if !sort.StringsAreSorted(data[0:]) {
    76  		t.Errorf("sorted %v", strings)
    77  		t.Errorf("   got %v", data)
    78  	}
    79  }
    80  
    81  /*
    82  func TestSlice(t *testing.T) {
    83  	data := strings
    84  	Slice(data[:], func(i, j int) bool {
    85  		return data[i] < data[j]
    86  	})
    87  	if !SliceIsSorted(data[:], func(i, j int) bool { return data[i] < data[j] }) {
    88  		t.Errorf("sorted %v", strings)
    89  		t.Errorf("   got %v", data)
    90  	}
    91  }
    92  */
    93  
    94  func TestSortLarge_Random(t *testing.T) {
    95  	n := 1000000
    96  	if testing.Short() {
    97  		n /= 100
    98  	}
    99  	data := make([]int, n)
   100  	for i := 0; i < len(data); i++ {
   101  		data[i] = rand.Intn(100)
   102  	}
   103  	if sort.IntsAreSorted(data) {
   104  		t.Fatalf("terrible rand.rand")
   105  	}
   106  	sort.Ints(data)
   107  	if !sort.IntsAreSorted(data) {
   108  		t.Errorf("sort didn't sort - 1M ints")
   109  	}
   110  }
   111  
   112  /*
   113  func TestReverseSortIntSlice(t *testing.T) {
   114  	data := ints
   115  	data1 := ints
   116  	a := IntSlice(data[0:])
   117  	Sort(a)
   118  	r := IntSlice(data1[0:])
   119  	Sort(Reverse(r))
   120  	for i := 0; i < len(data); i++ {
   121  		if a[i] != r[len(data)-1-i] {
   122  			t.Errorf("reverse sort didn't sort")
   123  		}
   124  		if i > len(data)/2 {
   125  			break
   126  		}
   127  	}
   128  }
   129  */
   130  
   131  type nonDeterministicTestingData struct {
   132  	r *rand.Rand
   133  }
   134  
   135  func (t *nonDeterministicTestingData) Len() int {
   136  	return 500
   137  }
   138  
   139  func (t *nonDeterministicTestingData) Less(i, j int) bool {
   140  	if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
   141  		panic("nondeterministic comparison out of bounds")
   142  	}
   143  	return t.r.Int()%2 == 0
   144  	// return t.r.Float32() < 0.5
   145  }
   146  
   147  func (t *nonDeterministicTestingData) Swap(i, j int) {
   148  	if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
   149  		panic("nondeterministic comparison out of bounds")
   150  	}
   151  }
   152  
   153  func TestNonDeterministicComparison(t *testing.T) {
   154  	// Ensure that sort.Sort does not panic when Less returns inconsistent results.
   155  	// See https://golang.org/issue/14377.
   156  	defer func() {
   157  		if r := recover(); r != nil {
   158  			t.Error(r)
   159  		}
   160  	}()
   161  
   162  	td := &nonDeterministicTestingData{
   163  		r: rand.New(rand.NewSource(0)),
   164  	}
   165  
   166  	for i := 0; i < 10; i++ {
   167  		sort.Sort(td)
   168  	}
   169  }
   170  
   171  func BenchmarkSortString1K(b *testing.B) {
   172  	b.StopTimer()
   173  	unsorted := make([]string, 1<<10)
   174  	for i := range unsorted {
   175  		unsorted[i] = strconv.Itoa(i ^ 0x2cc)
   176  	}
   177  	data := make([]string, len(unsorted))
   178  
   179  	for i := 0; i < b.N; i++ {
   180  		copy(data, unsorted)
   181  		b.StartTimer()
   182  		sort.Strings(data)
   183  		b.StopTimer()
   184  	}
   185  }
   186  
   187  /*
   188  func BenchmarkSortString1K_Slice(b *testing.B) {
   189  	b.StopTimer()
   190  	unsorted := make([]string, 1<<10)
   191  	for i := range unsorted {
   192  		unsorted[i] = strconv.Itoa(i ^ 0x2cc)
   193  	}
   194  	data := make([]string, len(unsorted))
   195  
   196  	for i := 0; i < b.N; i++ {
   197  		copy(data, unsorted)
   198  		b.StartTimer()
   199  		Slice(data, func(i, j int) bool { return data[i] < data[j] })
   200  		b.StopTimer()
   201  	}
   202  }
   203  
   204  func BenchmarkStableString1K(b *testing.B) {
   205  	b.StopTimer()
   206  	unsorted := make([]string, 1<<10)
   207  	for i := range unsorted {
   208  		unsorted[i] = strconv.Itoa(i ^ 0x2cc)
   209  	}
   210  	data := make([]string, len(unsorted))
   211  
   212  	for i := 0; i < b.N; i++ {
   213  		copy(data, unsorted)
   214  		b.StartTimer()
   215  		Stable(StringSlice(data))
   216  		b.StopTimer()
   217  	}
   218  }
   219  */
   220  
   221  func BenchmarkSortInt1K(b *testing.B) {
   222  	b.StopTimer()
   223  	for i := 0; i < b.N; i++ {
   224  		data := make([]int, 1<<10)
   225  		for i := 0; i < len(data); i++ {
   226  			data[i] = i ^ 0x2cc
   227  		}
   228  		b.StartTimer()
   229  		sort.Ints(data)
   230  		b.StopTimer()
   231  	}
   232  }
   233  
   234  /*
   235  func BenchmarkStableInt1K(b *testing.B) {
   236  	b.StopTimer()
   237  	unsorted := make([]int, 1<<10)
   238  	for i := range unsorted {
   239  		unsorted[i] = i ^ 0x2cc
   240  	}
   241  	data := make([]int, len(unsorted))
   242  	for i := 0; i < b.N; i++ {
   243  		copy(data, unsorted)
   244  		b.StartTimer()
   245  		Stable(IntSlice(data))
   246  		b.StopTimer()
   247  	}
   248  }
   249  
   250  func BenchmarkStableInt1K_Slice(b *testing.B) {
   251  	b.StopTimer()
   252  	unsorted := make([]int, 1<<10)
   253  	for i := range unsorted {
   254  		unsorted[i] = i ^ 0x2cc
   255  	}
   256  	data := make([]int, len(unsorted))
   257  	for i := 0; i < b.N; i++ {
   258  		copy(data, unsorted)
   259  		b.StartTimer()
   260  		SliceStable(data, func(i, j int) bool { return data[i] < data[j] })
   261  		b.StopTimer()
   262  	}
   263  }
   264  
   265  func BenchmarkSortInt64K(b *testing.B) {
   266  	b.StopTimer()
   267  	for i := 0; i < b.N; i++ {
   268  		data := make([]int, 1<<16)
   269  		for i := 0; i < len(data); i++ {
   270  			data[i] = i ^ 0xcccc
   271  		}
   272  		b.StartTimer()
   273  		Ints(data)
   274  		b.StopTimer()
   275  	}
   276  }
   277  
   278  func BenchmarkSortInt64K_Slice(b *testing.B) {
   279  	b.StopTimer()
   280  	for i := 0; i < b.N; i++ {
   281  		data := make([]int, 1<<16)
   282  		for i := 0; i < len(data); i++ {
   283  			data[i] = i ^ 0xcccc
   284  		}
   285  		b.StartTimer()
   286  		Slice(data, func(i, j int) bool { return data[i] < data[j] })
   287  		b.StopTimer()
   288  	}
   289  }
   290  
   291  func BenchmarkStableInt64K(b *testing.B) {
   292  	b.StopTimer()
   293  	for i := 0; i < b.N; i++ {
   294  		data := make([]int, 1<<16)
   295  		for i := 0; i < len(data); i++ {
   296  			data[i] = i ^ 0xcccc
   297  		}
   298  		b.StartTimer()
   299  		Stable(IntSlice(data))
   300  		b.StopTimer()
   301  	}
   302  }
   303  */
   304  
   305  const (
   306  	_Sawtooth = iota
   307  	_Rand
   308  	_Stagger
   309  	_Plateau
   310  	_Shuffle
   311  	_NDist
   312  )
   313  
   314  const (
   315  	_Copy = iota
   316  	_Reverse
   317  	_ReverseFirstHalf
   318  	_ReverseSecondHalf
   319  	_Sorted
   320  	_Dither
   321  	_NMode
   322  )
   323  
   324  type testingData struct {
   325  	desc        string
   326  	t           *testing.T
   327  	data        []int
   328  	maxswap     int // number of swaps allowed
   329  	ncmp, nswap int
   330  }
   331  
   332  func (d *testingData) Len() int { return len(d.data) }
   333  func (d *testingData) Less(i, j int) bool {
   334  	d.ncmp++
   335  	return d.data[i] < d.data[j]
   336  }
   337  
   338  func (d *testingData) Swap(i, j int) {
   339  	if d.nswap >= d.maxswap {
   340  		d.t.Fatalf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data))
   341  	}
   342  	d.nswap++
   343  	d.data[i], d.data[j] = d.data[j], d.data[i]
   344  }
   345  
   346  func min(a, b int) int {
   347  	if a < b {
   348  		return a
   349  	}
   350  	return b
   351  }
   352  
   353  func lg(n int) int {
   354  	i := 0
   355  	for 1<<uint(i) < n {
   356  		i++
   357  	}
   358  	return i
   359  }
   360  
   361  func testBentleyMcIlroy(t *testing.T, sortFn func(sort.Interface), maxswap func(int) int) {
   362  	sizes := []int{100, 1023, 1024, 1025}
   363  	if testing.Short() {
   364  		sizes = []int{100, 127, 128, 129}
   365  	}
   366  	dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
   367  	modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
   368  	var tmp1, tmp2 [1025]int
   369  	for _, n := range sizes {
   370  		for m := 1; m < 2*n; m *= 2 {
   371  			for dist := 0; dist < _NDist; dist++ {
   372  				j := 0
   373  				k := 1
   374  				data := tmp1[0:n]
   375  				for i := 0; i < n; i++ {
   376  					switch dist {
   377  					case _Sawtooth:
   378  						data[i] = i % m
   379  					case _Rand:
   380  						data[i] = rand.Intn(m)
   381  					case _Stagger:
   382  						data[i] = (i*m + i) % n
   383  					case _Plateau:
   384  						data[i] = min(i, m)
   385  					case _Shuffle:
   386  						if rand.Intn(m) != 0 {
   387  							j += 2
   388  							data[i] = j
   389  						} else {
   390  							k += 2
   391  							data[i] = k
   392  						}
   393  					}
   394  				}
   395  
   396  				mdata := tmp2[0:n]
   397  				for mode := 0; mode < _NMode; mode++ {
   398  					switch mode {
   399  					case _Copy:
   400  						for i := 0; i < n; i++ {
   401  							mdata[i] = data[i]
   402  						}
   403  					case _Reverse:
   404  						for i := 0; i < n; i++ {
   405  							mdata[i] = data[n-i-1]
   406  						}
   407  					case _ReverseFirstHalf:
   408  						for i := 0; i < n/2; i++ {
   409  							mdata[i] = data[n/2-i-1]
   410  						}
   411  						for i := n / 2; i < n; i++ {
   412  							mdata[i] = data[i]
   413  						}
   414  					case _ReverseSecondHalf:
   415  						for i := 0; i < n/2; i++ {
   416  							mdata[i] = data[i]
   417  						}
   418  						for i := n / 2; i < n; i++ {
   419  							mdata[i] = data[n-(i-n/2)-1]
   420  						}
   421  					case _Sorted:
   422  						for i := 0; i < n; i++ {
   423  							mdata[i] = data[i]
   424  						}
   425  						// Ints is known to be correct
   426  						// because mode Sort runs after mode _Copy.
   427  						sort.Ints(mdata)
   428  					case _Dither:
   429  						for i := 0; i < n; i++ {
   430  							mdata[i] = data[i] + i%5
   431  						}
   432  					}
   433  
   434  					desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode])
   435  					d := &testingData{desc: desc, t: t, data: mdata[0:n], maxswap: maxswap(n)}
   436  					sortFn(d)
   437  					// Uncomment if you are trying to improve the number of compares/swaps.
   438  					// t.Logf("%s: ncmp=%d, nswp=%d", desc, d.ncmp, d.nswap)
   439  
   440  					// If we were testing C qsort, we'd have to make a copy
   441  					// of the slice and sort it ourselves and then compare
   442  					// x against it, to ensure that qsort was only permuting
   443  					// the data, not (for example) overwriting it with zeros.
   444  					//
   445  					// In go, we don't have to be so paranoid: since the only
   446  					// mutating method Sort can call is TestingData.swap,
   447  					// it suffices here just to check that the final slice is sorted.
   448  					if !sort.IntsAreSorted(mdata) {
   449  						t.Fatalf("%s: ints not sorted\n\t%v", desc, mdata)
   450  					}
   451  				}
   452  			}
   453  		}
   454  	}
   455  }
   456  
   457  func TestSortBM(t *testing.T) {
   458  	testBentleyMcIlroy(t, sort.Sort, func(n int) int { return n * lg(n) * 12 / 10 })
   459  }
   460  
   461  /* removed because sort.Heapsort removed
   462  func TestHeapsortBM(t *testing.T) {
   463  	testBentleyMcIlroy(t, sort.Heapsort, func(n int) int { return n * lg(n) * 12 / 10 })
   464  }
   465  */
   466  
   467  func TestStableBM(t *testing.T) {
   468  	testBentleyMcIlroy(t, sort.Stable, func(n int) int { return n * lg(n) * lg(n) / 3 })
   469  }
   470  
   471  // This is based on the "antiquicksort" implementation by M. Douglas McIlroy.
   472  // See https://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info.
   473  type adversaryTestingData struct {
   474  	t         *testing.T
   475  	data      []int // item values, initialized to special gas value and changed by Less
   476  	maxcmp    int   // number of comparisons allowed
   477  	ncmp      int   // number of comparisons (calls to Less)
   478  	nsolid    int   // number of elements that have been set to non-gas values
   479  	candidate int   // guess at current pivot
   480  	gas       int   // special value for unset elements, higher than everything else
   481  }
   482  
   483  func (d *adversaryTestingData) Len() int { return len(d.data) }
   484  
   485  func (d *adversaryTestingData) Less(i, j int) bool {
   486  	if d.ncmp >= d.maxcmp {
   487  		d.t.Fatalf("used %d comparisons sorting adversary data with size %d", d.ncmp, len(d.data))
   488  	}
   489  	d.ncmp++
   490  
   491  	if d.data[i] == d.gas && d.data[j] == d.gas {
   492  		if i == d.candidate {
   493  			// freeze i
   494  			d.data[i] = d.nsolid
   495  			d.nsolid++
   496  		} else {
   497  			// freeze j
   498  			d.data[j] = d.nsolid
   499  			d.nsolid++
   500  		}
   501  	}
   502  
   503  	if d.data[i] == d.gas {
   504  		d.candidate = i
   505  	} else if d.data[j] == d.gas {
   506  		d.candidate = j
   507  	}
   508  
   509  	return d.data[i] < d.data[j]
   510  }
   511  
   512  func (d *adversaryTestingData) Swap(i, j int) {
   513  	d.data[i], d.data[j] = d.data[j], d.data[i]
   514  }
   515  
   516  func newAdversaryTestingData(t *testing.T, size int, maxcmp int) *adversaryTestingData {
   517  	gas := size - 1
   518  	data := make([]int, size)
   519  	for i := 0; i < size; i++ {
   520  		data[i] = gas
   521  	}
   522  	return &adversaryTestingData{t: t, data: data, maxcmp: maxcmp, gas: gas}
   523  }
   524  
   525  func TestAdversary(t *testing.T) {
   526  	const size = 10000            // large enough to distinguish between O(n^2) and O(n*log(n))
   527  	maxcmp := size * lg(size) * 4 // the factor 4 was found by trial and error
   528  	d := newAdversaryTestingData(t, size, maxcmp)
   529  	sort.Sort(d) // This should degenerate to heapsort.
   530  	// Check data is fully populated and sorted.
   531  	for i, v := range d.data {
   532  		if v != i {
   533  			t.Fatalf("adversary data not fully sorted")
   534  		}
   535  	}
   536  }
   537  
   538  /*
   539  func TestStableInts(t *testing.T) {
   540  	data := ints
   541  	Stable(IntSlice(data[0:]))
   542  	if !IntsAreSorted(data[0:]) {
   543  		t.Errorf("nsorted %v\n   got %v", ints, data)
   544  	}
   545  }
   546  */
   547  
   548  type intPairs []struct {
   549  	a, b int
   550  }
   551  
   552  // IntPairs compare on a only.
   553  func (d intPairs) Len() int           { return len(d) }
   554  func (d intPairs) Less(i, j int) bool { return d[i].a < d[j].a }
   555  func (d intPairs) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
   556  
   557  // Record initial order in B.
   558  func (d intPairs) initB() {
   559  	for i := range d {
   560  		d[i].b = i
   561  	}
   562  }
   563  
   564  // InOrder checks if a-equal elements were not reordered.
   565  func (d intPairs) inOrder() bool {
   566  	lastA, lastB := -1, 0
   567  	for i := 0; i < len(d); i++ {
   568  		if lastA != d[i].a {
   569  			lastA = d[i].a
   570  			lastB = d[i].b
   571  			continue
   572  		}
   573  		if d[i].b <= lastB {
   574  			return false
   575  		}
   576  		lastB = d[i].b
   577  	}
   578  	return true
   579  }
   580  
   581  func TestStability(t *testing.T) {
   582  	n, m := 100000, 1000
   583  	if testing.Short() {
   584  		n, m = 1000, 100
   585  	}
   586  	data := make(intPairs, n)
   587  
   588  	// random distribution
   589  	for i := 0; i < len(data); i++ {
   590  		data[i].a = rand.Intn(m)
   591  	}
   592  	if sort.IsSorted(data) {
   593  		t.Fatalf("terrible rand.rand")
   594  	}
   595  	data.initB()
   596  	sort.Stable(data)
   597  	if !sort.IsSorted(data) {
   598  		t.Errorf("Stable didn't sort %d ints", n)
   599  	}
   600  	if !data.inOrder() {
   601  		t.Errorf("Stable wasn't stable on %d ints", n)
   602  	}
   603  
   604  	// already sorted
   605  	data.initB()
   606  	sort.Stable(data)
   607  	if !sort.IsSorted(data) {
   608  		t.Errorf("Stable shuffled sorted %d ints (order)", n)
   609  	}
   610  	if !data.inOrder() {
   611  		t.Errorf("Stable shuffled sorted %d ints (stability)", n)
   612  	}
   613  
   614  	// sorted reversed
   615  	for i := 0; i < len(data); i++ {
   616  		data[i].a = len(data) - i
   617  	}
   618  	data.initB()
   619  	sort.Stable(data)
   620  	if !sort.IsSorted(data) {
   621  		t.Errorf("Stable didn't sort %d ints", n)
   622  	}
   623  	if !data.inOrder() {
   624  		t.Errorf("Stable wasn't stable on %d ints", n)
   625  	}
   626  }
   627  
   628  var countOpsSizes = []int{1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6}
   629  
   630  func countOps(t *testing.T, algo func(sort.Interface), name string) {
   631  	sizes := countOpsSizes
   632  	if testing.Short() {
   633  		sizes = sizes[:5]
   634  	}
   635  	if !testing.Verbose() {
   636  		t.Skip("Counting skipped as non-verbose mode.")
   637  	}
   638  	for _, n := range sizes {
   639  		td := testingData{
   640  			desc:    name,
   641  			t:       t,
   642  			data:    make([]int, n),
   643  			maxswap: 1<<31 - 1,
   644  		}
   645  		for i := 0; i < n; i++ {
   646  			td.data[i] = rand.Intn(n / 5)
   647  		}
   648  		algo(&td)
   649  		t.Logf("%s %8d elements: %11d Swap, %10d Less", name, n, td.nswap, td.ncmp)
   650  	}
   651  }
   652  
   653  func TestCountStableOps(t *testing.T) { countOps(t, sort.Stable, "Stable") }
   654  func TestCountSortOps(t *testing.T)   { countOps(t, sort.Sort, "Sort  ") }
   655  
   656  /* XXX removed due to testenv
   657  func bench(b *testing.B, size int, algo func(Interface), name string) {
   658  	if stringspkg.HasSuffix(testenv.Builder(), "-race") && size > 1e4 {
   659  		b.Skip("skipping slow benchmark on race builder")
   660  	}
   661  	b.StopTimer()
   662  	data := make(intPairs, size)
   663  	x := ^uint32(0)
   664  	for i := 0; i < b.N; i++ {
   665  		for n := size - 3; n <= size+3; n++ {
   666  			for i := 0; i < len(data); i++ {
   667  				x += x
   668  				x ^= 1
   669  				if int32(x) < 0 {
   670  					x ^= 0x88888eef
   671  				}
   672  				data[i].a = int(x % uint32(n/5))
   673  			}
   674  			data.initB()
   675  			b.StartTimer()
   676  			algo(data)
   677  			b.StopTimer()
   678  			if !IsSorted(data) {
   679  				b.Errorf("%s did not sort %d ints", name, n)
   680  			}
   681  			if name == "Stable" && !data.inOrder() {
   682  				b.Errorf("%s unstable on %d ints", name, n)
   683  			}
   684  		}
   685  	}
   686  }
   687  
   688  func BenchmarkSort1e2(b *testing.B)   { bench(b, 1e2, Sort, "Sort") }
   689  func BenchmarkStable1e2(b *testing.B) { bench(b, 1e2, Stable, "Stable") }
   690  func BenchmarkSort1e4(b *testing.B)   { bench(b, 1e4, Sort, "Sort") }
   691  func BenchmarkStable1e4(b *testing.B) { bench(b, 1e4, Stable, "Stable") }
   692  func BenchmarkSort1e6(b *testing.B)   { bench(b, 1e6, Sort, "Sort") }
   693  func BenchmarkStable1e6(b *testing.B) { bench(b, 1e6, Stable, "Stable") }
   694  
   695  */