mirror of
https://github.com/golang/go
synced 2024-11-24 21:50:11 -07:00
sort: fix for nondeterministic less function in quicksort pivot
Fixes #14377 Change-Id: I130a6e1b8bc827db44efd0a74e759b894ecc4977 Reviewed-on: https://go-review.googlesource.com/19823 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
50c38d46e8
commit
38d4511b10
@ -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) {
|
|||||||
// 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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++ {
|
||||||
|
Loading…
Reference in New Issue
Block a user