Commit e44998bc authored by Jure Ham's avatar Jure Ham Committed by Andrew Gerrand

sort: fix for nondeterministic less function in quicksort pivot

Fixes #14377

Change-Id: I130a6e1b8bc827db44efd0a74e759b894ecc4977
Reviewed-on: https://go-review.googlesource.com/19823Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/22039
parent 002cf282
...@@ -119,15 +119,15 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) { ...@@ -119,15 +119,15 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
pivot := lo pivot := lo
a, c := lo+1, hi-1 a, c := lo+1, hi-1
for ; a != c && data.Less(a, pivot); a++ { for ; a < c && data.Less(a, pivot); a++ {
} }
b := a b := a
for { for {
for ; b != c && !data.Less(pivot, b); b++ { // data[b] <= pivot for ; b < c && !data.Less(pivot, b); b++ { // data[b] <= pivot
} }
for ; b != c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot for ; b < c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
} }
if b == c { if b >= c {
break break
} }
// data[b] > pivot; data[c-1] <= pivot // data[b] > pivot; data[c-1] <= pivot
...@@ -167,11 +167,11 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) { ...@@ -167,11 +167,11 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
// data[a <= i < b] unexamined // data[a <= i < b] unexamined
// data[b <= i < c] = pivot // data[b <= i < c] = pivot
for { for {
for ; a != b && !data.Less(b-1, pivot); b-- { // data[b] == pivot for ; a < b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
} }
for ; a != b && data.Less(a, pivot); a++ { // data[a] < pivot for ; a < b && data.Less(a, pivot); a++ { // data[a] < pivot
} }
if a == b { if a >= b {
break break
} }
// data[a] == pivot; data[b-1] < pivot // data[a] == pivot; data[b-1] < pivot
......
...@@ -109,6 +109,43 @@ func TestReverseSortIntSlice(t *testing.T) { ...@@ -109,6 +109,43 @@ func TestReverseSortIntSlice(t *testing.T) {
} }
} }
type nonDeterministicTestingData struct {
r *rand.Rand
}
func (t *nonDeterministicTestingData) Len() int {
return 500
}
func (t *nonDeterministicTestingData) Less(i, j int) bool {
if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
panic("nondeterministic comparison out of bounds")
}
return t.r.Float32() < 0.5
}
func (t *nonDeterministicTestingData) Swap(i, j int) {
if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
panic("nondeterministic comparison out of bounds")
}
}
func TestNonDeterministicComparison(t *testing.T) {
// Ensure that sort.Sort does not panic when Less returns inconsistent results.
// See https://golang.org/issue/14377.
defer func() {
if r := recover(); r != nil {
t.Error(r)
}
}()
td := &nonDeterministicTestingData{
r: rand.New(rand.NewSource(0)),
}
for i := 0; i < 10; i++ {
Sort(td)
}
}
func BenchmarkSortString1K(b *testing.B) { func BenchmarkSortString1K(b *testing.B) {
b.StopTimer() b.StopTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment