1
0
mirror of https://github.com/golang/go synced 2024-11-05 23:36:12 -07:00

sort: forward fixed-type slice sorting to slices package

Forwards the following functions to the slices package:

    sort.Ints
    sort.Strings
    sort.Float64s
    sort.IntsAreSorted
    sort.StringsAreSorted
    sort.Float64sAreSorted

benchstat results on the sort package's benchmarks:

goos: linux
goarch: amd64
pkg: sort
cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
SearchWrappers-8        58.10n ± 0%   58.43n ± 1%   +0.57% (p=0.004 n=10)
SortString1K-8          76.53µ ± 1%   66.04µ ± 2%  -13.71% (p=0.000 n=10)
SortString1K_Slice-8    71.99µ ± 1%   72.32µ ± 2%        ~ (p=0.481 n=10)
StableString1K-8        92.66µ ± 1%   92.10µ ± 2%   -0.61% (p=0.019 n=10)
SortInt1K-8             34.31µ ± 0%   11.49µ ± 2%  -66.50% (p=0.000 n=10)
SortInt1K_Sorted-8     2699.5n ± 1%   959.0n ± 3%  -64.47% (p=0.000 n=10)
SortInt1K_Reversed-8    3.990µ ± 1%   1.429µ ± 4%  -64.19% (p=0.000 n=10)
SortInt1K_Mod8-8       13.695µ ± 1%   5.129µ ± 2%  -62.55% (p=0.000 n=10)
StableInt1K-8           46.22µ ± 1%   46.80µ ± 1%        ~ (p=0.109 n=10)
StableInt1K_Slice-8     44.12µ ± 1%   44.32µ ± 2%        ~ (p=0.315 n=10)
SortInt64K-8            3.848m ± 0%   1.857m ± 2%  -51.76% (p=0.000 n=10)
SortInt64K_Slice-8      3.690m ± 0%   3.740m ± 0%   +1.36% (p=0.002 n=10)
StableInt64K-8          3.901m ± 0%   3.917m ± 0%   +0.42% (p=0.003 n=10)
Sort1e2-8               32.22µ ± 2%   32.40µ ± 2%        ~ (p=0.529 n=10)
Stable1e2-8             54.11µ ± 1%   54.11µ ± 1%        ~ (p=0.796 n=10)
Sort1e4-8               5.998m ± 1%   5.993m ± 1%        ~ (p=0.579 n=10)
Stable1e4-8             15.23m ± 0%   15.32m ± 0%   +0.59% (p=0.000 n=10)
Sort1e6-8               902.8m ± 0%   904.3m ± 0%        ~ (p=0.075 n=10)
Stable1e6-8              3.089 ± 0%    3.089 ± 0%        ~ (p=0.971 n=10)
geomean                 259.8µ        200.0µ       -22.99%

Most of the benchmarks are unaffected. The ones with significant reductions
are precisely for the functions that were forwarded.

This CL has to move some things around to avoid a circular dependency
between sort and slices. Since sort depends on slices now, nothing in
slices can depend on sort - not even in tests.

Fixes #61180

Change-Id: Ic0e5f519863d96a139fada08aefb1bcdf4c7a9a3
Reviewed-on: https://go-review.googlesource.com/c/go/+/508135
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Eli Bendersky <eliben@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Eli Bendersky 2023-07-06 08:19:25 -07:00 committed by Eli Bendersky
parent 12f3d6858e
commit c3da3bcd8e
10 changed files with 297 additions and 301 deletions

View File

@ -77,8 +77,15 @@ var depsRules = `
< internal/oserror, math/bits
< RUNTIME;
RUNTIME
< sort
# slices depends on unsafe for overlapping check, cmp for comparison
# semantics, and math/bits for # calculating bitlength of numbers.
unsafe, cmp, math/bits
< slices;
RUNTIME, slices
< sort;
sort
< container/heap;
RUNTIME
@ -223,11 +230,6 @@ var depsRules = `
< hash
< hash/adler32, hash/crc32, hash/crc64, hash/fnv;
# slices depends on unsafe for overlapping check, cmp for comparison
# semantics, and math/bits for # calculating bitlength of numbers.
unsafe, cmp, math/bits
< slices;
# math/big
FMT, encoding/binary, math/rand
< math/big;

View File

@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slices
package slices_test
import (
"cmp"
"internal/race"
"internal/testenv"
"math"
. "slices"
"strings"
"testing"
)
@ -999,25 +1000,6 @@ func BenchmarkReplace(b *testing.B) {
}
func TestRotate(t *testing.T) {
const N = 10
s := make([]int, 0, N)
for n := 0; n < N; n++ {
for r := 0; r < n; r++ {
s = s[:0]
for i := 0; i < n; i++ {
s = append(s, i)
}
rotateLeft(s, r)
for i := 0; i < n; i++ {
if s[i] != (i+r)%n {
t.Errorf("expected n=%d r=%d i:%d want:%d got:%d", n, r, i, (i+r)%n, s[i])
}
}
}
}
}
func TestInsertGrowthRate(t *testing.T) {
b := make([]byte, 1)
maxCap := cap(b)

View File

@ -2,252 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slices
package slices_test
import (
"fmt"
"math/rand"
"sort"
"strconv"
"strings"
"slices"
"testing"
)
// These benchmarks compare sorting a large slice of int with sort.Ints vs.
// slices.Sort
func makeRandomInts(n int) []int {
rand.Seed(42)
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = rand.Intn(n)
}
return ints
}
func makeSortedInts(n int) []int {
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = i
}
return ints
}
func makeReversedInts(n int) []int {
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = n - i
}
return ints
}
const N = 100_000
func BenchmarkSortInts(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeRandomInts(N)
b.StartTimer()
sort.Ints(ints)
}
}
func makeSortedStrings(n int) []string {
x := make([]string, n)
for i := 0; i < n; i++ {
x[i] = strconv.Itoa(i)
}
Sort(x)
return x
}
func BenchmarkSlicesSortInts(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeRandomInts(N)
b.StartTimer()
Sort(ints)
}
}
func BenchmarkSlicesSortInts_Sorted(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeSortedInts(N)
b.StartTimer()
Sort(ints)
}
}
func BenchmarkSlicesSortInts_Reversed(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeReversedInts(N)
b.StartTimer()
Sort(ints)
}
}
func BenchmarkIntsAreSorted(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeSortedInts(N)
b.StartTimer()
sort.IntsAreSorted(ints)
}
}
func BenchmarkIsSorted(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeSortedInts(N)
b.StartTimer()
IsSorted(ints)
}
}
// Since we're benchmarking these sorts against each other, make sure that they
// generate similar results.
func TestIntSorts(t *testing.T) {
ints := makeRandomInts(200)
ints2 := Clone(ints)
sort.Ints(ints)
Sort(ints2)
for i := range ints {
if ints[i] != ints2[i] {
t.Fatalf("ints2 mismatch at %d; %d != %d", i, ints[i], ints2[i])
}
}
}
// The following is a benchmark for sorting strings.
// makeRandomStrings generates n random strings with alphabetic runes of
// varying lengths.
func makeRandomStrings(n int) []string {
rand.Seed(42)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
ss := make([]string, n)
for i := 0; i < n; i++ {
var sb strings.Builder
slen := 2 + rand.Intn(50)
for j := 0; j < slen; j++ {
sb.WriteRune(letters[rand.Intn(len(letters))])
}
ss[i] = sb.String()
}
return ss
}
func TestStringSorts(t *testing.T) {
ss := makeRandomStrings(200)
ss2 := Clone(ss)
sort.Strings(ss)
Sort(ss2)
for i := range ss {
if ss[i] != ss2[i] {
t.Fatalf("ss2 mismatch at %d; %s != %s", i, ss[i], ss2[i])
}
}
}
func BenchmarkSortStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStrings(N)
b.StartTimer()
sort.Strings(ss)
}
}
func BenchmarkSortStrings_Sorted(b *testing.B) {
ss := makeSortedStrings(N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
sort.Strings(ss)
}
}
func BenchmarkSlicesSortStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStrings(N)
b.StartTimer()
Sort(ss)
}
}
func BenchmarkSlicesSortStrings_Sorted(b *testing.B) {
ss := makeSortedStrings(N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sort(ss)
}
}
// These benchmarks compare sorting a slice of structs with sort.Sort vs.
// slices.SortFunc.
type myStruct struct {
a, b, c, d string
n int
}
type myStructs []*myStruct
func (s myStructs) Len() int { return len(s) }
func (s myStructs) Less(i, j int) bool { return s[i].n < s[j].n }
func (s myStructs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func makeRandomStructs(n int) myStructs {
rand.Seed(42)
structs := make([]*myStruct, n)
for i := 0; i < n; i++ {
structs[i] = &myStruct{n: rand.Intn(n)}
}
return structs
}
func TestStructSorts(t *testing.T) {
ss := makeRandomStructs(200)
ss2 := make([]*myStruct, len(ss))
for i := range ss {
ss2[i] = &myStruct{n: ss[i].n}
}
sort.Sort(ss)
SortFunc(ss2, func(a, b *myStruct) int { return a.n - b.n })
for i := range ss {
if *ss[i] != *ss2[i] {
t.Fatalf("ints2 mismatch at %d; %v != %v", i, *ss[i], *ss2[i])
}
}
}
func BenchmarkSortStructs(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStructs(N)
b.StartTimer()
sort.Sort(ss)
}
}
func BenchmarkSortFuncStructs(b *testing.B) {
cmpFunc := func(a, b *myStruct) int { return a.n - b.n }
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStructs(N)
b.StartTimer()
SortFunc(ss, cmpFunc)
}
}
func BenchmarkBinarySearchFloats(b *testing.B) {
for _, size := range []int{16, 32, 64, 128, 512, 1024} {
b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
@ -259,12 +21,17 @@ func BenchmarkBinarySearchFloats(b *testing.B) {
needle := (floats[midpoint] + floats[midpoint+1]) / 2
b.ResetTimer()
for i := 0; i < b.N; i++ {
BinarySearch(floats, needle)
slices.BinarySearch(floats, needle)
}
})
}
}
type myStruct struct {
a, b, c, d string
n int
}
func BenchmarkBinarySearchFuncStruct(b *testing.B) {
for _, size := range []int{16, 32, 64, 128, 512, 1024} {
b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
@ -277,7 +44,7 @@ func BenchmarkBinarySearchFuncStruct(b *testing.B) {
lessFunc := func(a, b *myStruct) int { return a.n - b.n }
b.ResetTimer()
for i := 0; i < b.N; i++ {
BinarySearchFunc(structs, needle, lessFunc)
slices.BinarySearchFunc(structs, needle, lessFunc)
}
})
}

View File

@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slices
package slices_test
import (
"cmp"
"fmt"
"math"
"math/rand"
"sort"
. "slices"
"strconv"
"strings"
"testing"
@ -17,7 +17,6 @@ import (
var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8, 74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3}
var float64sWithNaNs = [...]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}
var strs = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
func TestSortIntSlice(t *testing.T) {
@ -47,23 +46,6 @@ func TestSortFloat64Slice(t *testing.T) {
}
}
func TestSortFloat64SliceWithNaNs(t *testing.T) {
data := float64sWithNaNs[:]
data2 := Clone(data)
Sort(data)
sort.Float64s(data2)
if !IsSorted(data) {
t.Error("IsSorted indicates data isn't sorted")
}
// Compare for equality using cmp.Compare, which considers NaNs equal.
if !EqualFunc(data, data2, func(a, b float64) bool { return cmp.Compare(a, b) == 0 }) {
t.Errorf("mismatch between Sort and sort.Float64: got %v, want %v", data, data2)
}
}
func TestSortStringSlice(t *testing.T) {
data := Clone(strs[:])
Sort(data)

View File

@ -18,6 +18,9 @@ import (
//
// The less function must satisfy the same requirements as
// the Interface type's Less method.
//
// Note: in many situations, the newer slices.SortFunc function is more
// ergonomic and runs faster.
func Slice(x any, less func(i, j int) bool) {
rv := reflectlite.ValueOf(x)
swap := reflectlite.Swapper(x)
@ -32,6 +35,9 @@ func Slice(x any, less func(i, j int) bool) {
//
// The less function must satisfy the same requirements as
// the Interface type's Less method.
//
// Note: in many situations, the newer slices.SortStableFunc function is more
// ergonomic and runs faster.
func SliceStable(x any, less func(i, j int) bool) {
rv := reflectlite.ValueOf(x)
swap := reflectlite.Swapper(x)
@ -40,6 +46,9 @@ func SliceStable(x any, less func(i, j int) bool) {
// SliceIsSorted reports whether the slice x is sorted according to the provided less function.
// It panics if x is not a slice.
//
// Note: in many situations, the newer slices.IsSortedFunc function is more
// ergonomic and runs faster.
func SliceIsSorted(x any, less func(i, j int) bool) bool {
rv := reflectlite.ValueOf(x)
n := rv.Len()

View File

@ -161,35 +161,35 @@ func (x StringSlice) Sort() { Sort(x) }
// Ints sorts a slice of ints in increasing order.
//
// Note: consider using the newer slices.Sort function, which runs faster.
func Ints(x []int) { Sort(IntSlice(x)) }
// Note: as of Go 1.22, this function simply calls slices.Sort.
func Ints(x []int) { intsImpl(x) }
// Float64s sorts a slice of float64s in increasing order.
// Not-a-number (NaN) values are ordered before other values.
//
// Note: consider using the newer slices.Sort function, which runs faster.
func Float64s(x []float64) { Sort(Float64Slice(x)) }
// Note: as of Go 1.22, this function simply calls slices.Sort.
func Float64s(x []float64) { float64sImpl(x) }
// Strings sorts a slice of strings in increasing order.
//
// Note: consider using the newer slices.Sort function, which runs faster.
func Strings(x []string) { Sort(StringSlice(x)) }
// Note: as of Go 1.22, this function simply calls slices.Sort.
func Strings(x []string) { stringsImpl(x) }
// IntsAreSorted reports whether the slice x is sorted in increasing order.
//
// Note: consider using the newer slices.IsSorted function, which runs faster.
func IntsAreSorted(x []int) bool { return IsSorted(IntSlice(x)) }
// Note: as of Go 1.22, this function simply calls slices.IsSorted.
func IntsAreSorted(x []int) bool { return intsAreSortedImpl(x) }
// Float64sAreSorted reports whether the slice x is sorted in increasing order,
// with not-a-number (NaN) values before any other values.
//
// Note: consider using the newer slices.IsSorted function, which runs faster.
func Float64sAreSorted(x []float64) bool { return IsSorted(Float64Slice(x)) }
// Note: as of Go 1.22, this function simply calls slices.IsSorted.
func Float64sAreSorted(x []float64) bool { return float64sAreSortedImpl(x) }
// StringsAreSorted reports whether the slice x is sorted in increasing order.
//
// Note: consider using the newer slices.IsSorted function, which runs faster.
func StringsAreSorted(x []string) bool { return IsSorted(StringSlice(x)) }
// Note: as of Go 1.22, this function simply calls slices.IsSorted.
func StringsAreSorted(x []string) bool { return stringsAreSortedImpl(x) }
// Notes on stable sorting:
// The used algorithms are simple and provable correct on all input and use

15
src/sort/sort_impl_120.go Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.21
package sort
func intsImpl(x []int) { Sort(IntSlice(x)) }
func float64sImpl(x []float64) { Sort(Float64Slice(x)) }
func stringsImpl(x []string) { Sort(StringSlice(x)) }
func intsAreSortedImpl(x []int) bool { return IsSorted(IntSlice(x)) }
func float64sAreSortedImpl(x []float64) bool { return IsSorted(Float64Slice(x)) }
func stringsAreSortedImpl(x []string) bool { return IsSorted(StringSlice(x)) }

View File

@ -0,0 +1,22 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
// Starting with Go 1.21, we can leverage the new generic functions from the
// slices package to implement some `sort` functions faster. However, until
// the bootstrap compiler uses Go 1.21 or later, we keep a fallback version
// in sort_impl_120.go that retains the old implementation.
package sort
import "slices"
func intsImpl(x []int) { slices.Sort(x) }
func float64sImpl(x []float64) { slices.Sort(x) }
func stringsImpl(x []string) { slices.Sort(x) }
func intsAreSortedImpl(x []int) bool { return slices.IsSorted(x) }
func float64sAreSortedImpl(x []float64) bool { return slices.IsSorted(x) }
func stringsAreSortedImpl(x []string) bool { return slices.IsSorted(x) }

View File

@ -0,0 +1,201 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sort_test
import (
"math/rand"
"slices"
. "sort"
"strconv"
stringspkg "strings"
"testing"
)
// Benchmarks comparing sorting from the slices package with functions from
// the sort package (avoiding functions that are just forwarding to the slices
// package).
func makeRandomInts(n int) []int {
rand.Seed(42)
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = rand.Intn(n)
}
return ints
}
func makeSortedInts(n int) []int {
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = i
}
return ints
}
func makeReversedInts(n int) []int {
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = n - i
}
return ints
}
func makeSortedStrings(n int) []string {
x := make([]string, n)
for i := 0; i < n; i++ {
x[i] = strconv.Itoa(i)
}
Strings(x)
return x
}
const N = 100_000
func BenchmarkSortInts(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeRandomInts(N)
b.StartTimer()
Sort(IntSlice(ints))
}
}
func BenchmarkSlicesSortInts(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeRandomInts(N)
b.StartTimer()
slices.Sort(ints)
}
}
func BenchmarkSortIsSorted(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeSortedInts(N)
b.StartTimer()
IsSorted(IntSlice(ints))
}
}
func BenchmarkSlicesIsSorted(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ints := makeSortedInts(N)
b.StartTimer()
slices.IsSorted(ints)
}
}
// makeRandomStrings generates n random strings with alphabetic runes of
// varying lengths.
func makeRandomStrings(n int) []string {
rand.Seed(42)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
ss := make([]string, n)
for i := 0; i < n; i++ {
var sb stringspkg.Builder
slen := 2 + rand.Intn(50)
for j := 0; j < slen; j++ {
sb.WriteRune(letters[rand.Intn(len(letters))])
}
ss[i] = sb.String()
}
return ss
}
func BenchmarkSortStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStrings(N)
b.StartTimer()
Sort(StringSlice(ss))
}
}
func BenchmarkSlicesSortStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStrings(N)
b.StartTimer()
slices.Sort(ss)
}
}
func BenchmarkSortStrings_Sorted(b *testing.B) {
ss := makeSortedStrings(N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sort(StringSlice(ss))
}
}
func BenchmarkSlicesSortStrings_Sorted(b *testing.B) {
ss := makeSortedStrings(N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
slices.Sort(ss)
}
}
// These benchmarks compare sorting a slice of structs with sort.Sort vs.
// slices.SortFunc.
type myStruct struct {
a, b, c, d string
n int
}
type myStructs []*myStruct
func (s myStructs) Len() int { return len(s) }
func (s myStructs) Less(i, j int) bool { return s[i].n < s[j].n }
func (s myStructs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func makeRandomStructs(n int) myStructs {
rand.Seed(42)
structs := make([]*myStruct, n)
for i := 0; i < n; i++ {
structs[i] = &myStruct{n: rand.Intn(n)}
}
return structs
}
func TestStructSorts(t *testing.T) {
ss := makeRandomStructs(200)
ss2 := make([]*myStruct, len(ss))
for i := range ss {
ss2[i] = &myStruct{n: ss[i].n}
}
Sort(ss)
slices.SortFunc(ss2, func(a, b *myStruct) int { return a.n - b.n })
for i := range ss {
if *ss[i] != *ss2[i] {
t.Fatalf("ints2 mismatch at %d; %v != %v", i, *ss[i], *ss2[i])
}
}
}
func BenchmarkSortStructs(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStructs(N)
b.StartTimer()
Sort(ss)
}
}
func BenchmarkSortFuncStructs(b *testing.B) {
cmpFunc := func(a, b *myStruct) int { return a.n - b.n }
for i := 0; i < b.N; i++ {
b.StopTimer()
ss := makeRandomStructs(N)
b.StartTimer()
slices.SortFunc(ss, cmpFunc)
}
}

View File

@ -5,10 +5,12 @@
package sort_test
import (
"cmp"
"fmt"
"internal/testenv"
"math"
"math/rand"
"slices"
. "sort"
"strconv"
stringspkg "strings"
@ -39,6 +41,20 @@ func TestSortFloat64Slice(t *testing.T) {
}
}
// Compare Sort with slices.Sort sorting a float64 slice containing NaNs.
func TestSortFloat64sCompareSlicesSort(t *testing.T) {
slice1 := slices.Clone(float64s[:])
slice2 := slices.Clone(float64s[:])
Sort(Float64Slice(slice1))
slices.Sort(slice2)
// Compare for equality using cmp.Compare, which considers NaNs equal.
if !slices.EqualFunc(slice1, slice1, func(a, b float64) bool { return cmp.Compare(a, b) == 0 }) {
t.Errorf("mismatch between Sort and slices.Sort: got %v, want %v", slice1, slice2)
}
}
func TestSortStringSlice(t *testing.T) {
data := strings
a := StringSlice(data[0:])