diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-12-03 04:34:57 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-12-03 04:34:57 +0000 |
commit | e440a3286bc89368b8d3a8fd6accd47191790bf2 (patch) | |
tree | 38fe54a4f38ede5d949c915d66191f24a6fe5153 /libgo/go/sort | |
parent | a641ee368e2614349084a9a7bda2ec2b0b2bc1cf (diff) | |
download | gcc-e440a3286bc89368b8d3a8fd6accd47191790bf2.tar.gz |
Add Go frontend, libgo library, and Go testsuite.
gcc/:
* gcc.c (default_compilers): Add entry for ".go".
* common.opt: Add -static-libgo as a driver option.
* doc/install.texi (Configuration): Mention libgo as an option for
--enable-shared. Mention go as an option for --enable-languages.
* doc/invoke.texi (Overall Options): Mention .go as a file name
suffix. Mention go as a -x option.
* doc/frontends.texi (G++ and GCC): Mention Go as a supported
language.
* doc/sourcebuild.texi (Top Level): Mention libgo.
* doc/standards.texi (Standards): Add section on Go language.
Move references for other languages into their own section.
* doc/contrib.texi (Contributors): Mention that I contributed the
Go frontend.
gcc/testsuite/:
* lib/go.exp: New file.
* lib/go-dg.exp: New file.
* lib/go-torture.exp: New file.
* lib/target-supports.exp (check_compile): Match // Go.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167407 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/sort')
-rw-r--r-- | libgo/go/sort/sort.go | 198 | ||||
-rw-r--r-- | libgo/go/sort/sort_test.go | 267 |
2 files changed, 465 insertions, 0 deletions
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go new file mode 100644 index 00000000000..c5b848414a8 --- /dev/null +++ b/libgo/go/sort/sort.go @@ -0,0 +1,198 @@ +// Copyright 2009 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. + +// The sort package provides primitives for sorting arrays +// and user-defined collections. +package sort + +// A type, typically a collection, that satisfies sort.Interface can be +// sorted by the routines in this package. The methods require that the +// elements of the collection be enumerated by an integer index. +type Interface interface { + // Len is the number of elements in the collection. + Len() int + // Less returns whether the element with index i should sort + // before the element with index j. + Less(i, j int) bool + // Swap swaps the elements with indexes i and j. + Swap(i, j int) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// Insertion sort +func insertionSort(data Interface, a, b int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && data.Less(j, j-1); j-- { + data.Swap(j, j-1) + } + } +} + +// Quicksort, following Bentley and McIlroy, +// ``Engineering a Sort Function,'' SP&E November 1993. + +// Move the median of the three values data[a], data[b], data[c] into data[a]. +func medianOfThree(data Interface, a, b, c int) { + m0 := b + m1 := a + m2 := c + // bubble sort on 3 elements + if data.Less(m1, m0) { + data.Swap(m1, m0) + } + if data.Less(m2, m1) { + data.Swap(m2, m1) + } + if data.Less(m1, m0) { + data.Swap(m1, m0) + } + // now data[m0] <= data[m1] <= data[m2] +} + +func swapRange(data Interface, a, b, n int) { + for i := 0; i < n; i++ { + data.Swap(a+i, b+i) + } +} + +func doPivot(data Interface, lo, hi int) (midlo, midhi int) { + m := (lo + hi) / 2 + if hi-lo > 40 { + // Tukey's ``Ninther,'' median of three medians of three. + s := (hi - lo) / 8 + medianOfThree(data, lo, lo+s, lo+2*s) + medianOfThree(data, m, m-s, m+s) + medianOfThree(data, hi-1, hi-1-s, hi-1-2*s) + } + medianOfThree(data, lo, m, hi-1) + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo <= i < a] = pivot + // data[a <= i < b] < pivot + // data[b <= i < c] is unexamined + // data[c <= i < d] > pivot + // data[d <= i < hi] = pivot + // + // Once b meets c, can swap the "= pivot" sections + // into the middle of the array. + pivot := lo + a, b, c, d := lo+1, lo+1, hi, hi + for b < c { + if data.Less(b, pivot) { // data[b] < pivot + b++ + continue + } + if !data.Less(pivot, b) { // data[b] = pivot + data.Swap(a, b) + a++ + b++ + continue + } + if data.Less(pivot, c-1) { // data[c-1] > pivot + c-- + continue + } + if !data.Less(c-1, pivot) { // data[c-1] = pivot + data.Swap(c-1, d-1) + c-- + d-- + continue + } + // data[b] > pivot; data[c-1] < pivot + data.Swap(b, c-1) + b++ + c-- + } + + n := min(b-a, a-lo) + swapRange(data, lo, b-n, n) + + n = min(hi-d, d-c) + swapRange(data, c, hi-n, n) + + return lo + b - a, hi - (d - c) +} + +func quickSort(data Interface, a, b int) { + if b-a > 7 { + mlo, mhi := doPivot(data, a, b) + quickSort(data, a, mlo) + quickSort(data, mhi, b) + } else if b-a > 1 { + insertionSort(data, a, b) + } +} + +func Sort(data Interface) { quickSort(data, 0, data.Len()) } + + +func IsSorted(data Interface) bool { + n := data.Len() + for i := n - 1; i > 0; i-- { + if data.Less(i, i-1) { + return false + } + } + return true +} + + +// Convenience types for common cases + +// IntArray attaches the methods of Interface to []int, sorting in increasing order. +type IntArray []int + +func (p IntArray) Len() int { return len(p) } +func (p IntArray) Less(i, j int) bool { return p[i] < p[j] } +func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Sort is a convenience method. +func (p IntArray) Sort() { Sort(p) } + + +// FloatArray attaches the methods of Interface to []float, sorting in increasing order. +type FloatArray []float + +func (p FloatArray) Len() int { return len(p) } +func (p FloatArray) Less(i, j int) bool { return p[i] < p[j] } +func (p FloatArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Sort is a convenience method. +func (p FloatArray) Sort() { Sort(p) } + + +// StringArray attaches the methods of Interface to []string, sorting in increasing order. +type StringArray []string + +func (p StringArray) Len() int { return len(p) } +func (p StringArray) Less(i, j int) bool { return p[i] < p[j] } +func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Sort is a convenience method. +func (p StringArray) Sort() { Sort(p) } + + +// Convenience wrappers for common cases + +// SortInts sorts an array of ints in increasing order. +func SortInts(a []int) { Sort(IntArray(a)) } +// SortFloats sorts an array of floats in increasing order. +func SortFloats(a []float) { Sort(FloatArray(a)) } +// SortStrings sorts an array of strings in increasing order. +func SortStrings(a []string) { Sort(StringArray(a)) } + + +// IntsAreSorted tests whether an array of ints is sorted in increasing order. +func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) } +// FloatsAreSorted tests whether an array of floats is sorted in increasing order. +func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)) } +// StringsAreSorted tests whether an array of strings is sorted in increasing order. +func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) } diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go new file mode 100644 index 00000000000..2085a67c82a --- /dev/null +++ b/libgo/go/sort/sort_test.go @@ -0,0 +1,267 @@ +// Copyright 2009 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 + +import ( + "fmt" + "rand" + "strconv" + "testing" +) + + +var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} +var floats = [...]float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} +var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} + +func TestSortIntArray(t *testing.T) { + data := ints + a := IntArray(data[0:]) + Sort(a) + if !IsSorted(a) { + t.Errorf("sorted %v", ints) + t.Errorf(" got %v", data) + } +} + +func TestSortFloatArray(t *testing.T) { + data := floats + a := FloatArray(data[0:]) + Sort(a) + if !IsSorted(a) { + t.Errorf("sorted %v", floats) + t.Errorf(" got %v", data) + } +} + +func TestSortStringArray(t *testing.T) { + data := strings + a := StringArray(data[0:]) + Sort(a) + if !IsSorted(a) { + t.Errorf("sorted %v", strings) + t.Errorf(" got %v", data) + } +} + +func TestSortInts(t *testing.T) { + data := ints + SortInts(data[0:]) + if !IntsAreSorted(data[0:]) { + t.Errorf("sorted %v", ints) + t.Errorf(" got %v", data) + } +} + +func TestSortFloats(t *testing.T) { + data := floats + SortFloats(data[0:]) + if !FloatsAreSorted(data[0:]) { + t.Errorf("sorted %v", floats) + t.Errorf(" got %v", data) + } +} + +func TestSortStrings(t *testing.T) { + data := strings + SortStrings(data[0:]) + if !StringsAreSorted(data[0:]) { + t.Errorf("sorted %v", strings) + t.Errorf(" got %v", data) + } +} + +func TestSortLarge_Random(t *testing.T) { + data := make([]int, 1000000) + for i := 0; i < len(data); i++ { + data[i] = rand.Intn(100) + } + if IntsAreSorted(data) { + t.Fatalf("terrible rand.rand") + } + SortInts(data) + if !IntsAreSorted(data) { + t.Errorf("sort didn't sort - 1M ints") + } +} + +func BenchmarkSortString1K(b *testing.B) { + b.StopTimer() + for i := 0; i < b.N; i++ { + data := make([]string, 1<<10) + for i := 0; i < len(data); i++ { + data[i] = strconv.Itoa(i ^ 0x2cc) + } + b.StartTimer() + SortStrings(data) + b.StopTimer() + } +} + +func BenchmarkSortInt1K(b *testing.B) { + b.StopTimer() + for i := 0; i < b.N; i++ { + data := make([]int, 1<<10) + for i := 0; i < len(data); i++ { + data[i] = i ^ 0x2cc + } + b.StartTimer() + SortInts(data) + b.StopTimer() + } +} + +func BenchmarkSortInt64K(b *testing.B) { + b.StopTimer() + for i := 0; i < b.N; i++ { + data := make([]int, 1<<16) + for i := 0; i < len(data); i++ { + data[i] = i ^ 0xcccc + } + b.StartTimer() + SortInts(data) + b.StopTimer() + } +} + +const ( + _Sawtooth = iota + _Rand + _Stagger + _Plateau + _Shuffle + _NDist +) + +const ( + _Copy = iota + _Reverse + _ReverseFirstHalf + _ReverseSecondHalf + _Sorted + _Dither + _NMode +) + +type testingData struct { + desc string + t *testing.T + data []int + maxswap int // number of swaps allowed + nswap int +} + +func (d *testingData) Len() int { return len(d.data) } +func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j] } +func (d *testingData) Swap(i, j int) { + if d.nswap >= d.maxswap { + d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data)) + d.t.FailNow() + } + d.nswap++ + d.data[i], d.data[j] = d.data[j], d.data[i] +} + +func lg(n int) int { + i := 0 + for 1<<uint(i) < n { + i++ + } + return i +} + +func TestBentleyMcIlroy(t *testing.T) { + sizes := []int{100, 1023, 1024, 1025} + dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"} + modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"} + var tmp1, tmp2 [1025]int + for ni := 0; ni < len(sizes); ni++ { + n := sizes[ni] + for m := 1; m < 2*n; m *= 2 { + for dist := 0; dist < _NDist; dist++ { + j := 0 + k := 1 + data := tmp1[0:n] + for i := 0; i < n; i++ { + switch dist { + case _Sawtooth: + data[i] = i % m + case _Rand: + data[i] = rand.Intn(m) + case _Stagger: + data[i] = (i*m + i) % n + case _Plateau: + data[i] = min(i, m) + case _Shuffle: + if rand.Intn(m) != 0 { + j += 2 + data[i] = j + } else { + k += 2 + data[i] = k + } + } + } + + mdata := tmp2[0:n] + for mode := 0; mode < _NMode; mode++ { + switch mode { + case _Copy: + for i := 0; i < n; i++ { + mdata[i] = data[i] + } + case _Reverse: + for i := 0; i < n; i++ { + mdata[i] = data[n-i-1] + } + case _ReverseFirstHalf: + for i := 0; i < n/2; i++ { + mdata[i] = data[n/2-i-1] + } + for i := n / 2; i < n; i++ { + mdata[i] = data[i] + } + case _ReverseSecondHalf: + for i := 0; i < n/2; i++ { + mdata[i] = data[i] + } + for i := n / 2; i < n; i++ { + mdata[i] = data[n-(i-n/2)-1] + } + case _Sorted: + for i := 0; i < n; i++ { + mdata[i] = data[i] + } + // SortInts is known to be correct + // because mode Sort runs after mode _Copy. + SortInts(mdata) + case _Dither: + for i := 0; i < n; i++ { + mdata[i] = data[i] + i%5 + } + } + + desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode]) + d := &testingData{desc, t, mdata[0:n], n * lg(n) * 12 / 10, 0} + Sort(d) + + // If we were testing C qsort, we'd have to make a copy + // of the array and sort it ourselves and then compare + // x against it, to ensure that qsort was only permuting + // the data, not (for example) overwriting it with zeros. + // + // In go, we don't have to be so paranoid: since the only + // mutating method Sort can call is TestingData.swap, + // it suffices here just to check that the final array is sorted. + if !IntsAreSorted(mdata) { + t.Errorf("%s: ints not sorted", desc) + t.Errorf("\t%v", mdata) + t.FailNow() + } + } + } + } + } +} |