From: Marcel van Lohuizen Date: Wed, 23 Jan 2013 13:16:22 +0000 (+0100) Subject: exp/locale/collate: added functionality for sorting. X-Git-Tag: go1.1rc2~1302 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=34b533cd81dbad155a8e2265d91110434bbac2fb;p=gostls13.git exp/locale/collate: added functionality for sorting. Eliminates the need for the user to fiddle with keys. R=rsc CC=golang-dev https://golang.org/cl/7060051 --- diff --git a/src/pkg/exp/locale/collate/sort.go b/src/pkg/exp/locale/collate/sort.go new file mode 100644 index 0000000000..57b2efdfc2 --- /dev/null +++ b/src/pkg/exp/locale/collate/sort.go @@ -0,0 +1,90 @@ +// Copyright 2013 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 collate + +import ( + "bytes" + "sort" +) + +const ( + maxSortBuffer = 40960 + maxSortEntries = 4096 +) + +type swapper interface { + Swap(i, j int) +} + +type sorter struct { + buf *Buffer + keys [][]byte + src swapper +} + +func (s *sorter) init(n int) { + if s.buf == nil { + s.buf = &Buffer{} + s.buf.init() + } + if cap(s.keys) < n { + s.keys = make([][]byte, n) + } + s.keys = s.keys[0:n] +} + +func (s *sorter) clean() { + if len(s.buf.key) > maxSortBuffer { + s.buf.key = s.buf.buf[:0] + } + if len(s.keys) > maxSortEntries { + s.keys = nil + } +} + +func (s *sorter) sort(src swapper) { + s.src = src + sort.Sort(s) +} + +func (s sorter) Len() int { + return len(s.keys) +} + +func (s sorter) Less(i, j int) bool { + return bytes.Compare(s.keys[i], s.keys[j]) == -1 +} + +func (s sorter) Swap(i, j int) { + s.keys[i], s.keys[j] = s.keys[j], s.keys[i] + s.src.Swap(i, j) +} + +// A Lister can be sorted by Collator's Sort method. +type Lister interface { + Len() int + Swap(i, j int) + // Bytes returns the bytes of the text at index i. + Bytes(i int) []byte +} + +// Sort uses sort.Sort to sort the strings represented by x using the rules of c. +func (c *Collator) Sort(x Lister) { + n := x.Len() + c.sorter.init(n) + for i := 0; i < n; i++ { + c.sorter.keys[i] = c.Key(c.sorter.buf, x.Bytes(i)) + } + c.sorter.sort(x) +} + +// Strings sorts x using the rules of c. +func (c *Collator) Strings(x []string) { + c.sorter.init(len(x)) + for i, s := range x { + c.sorter.keys[i] = c.KeyFromString(c.sorter.buf, s) + } + c.sorter.sort(sort.StringSlice(x)) +} diff --git a/src/pkg/exp/locale/collate/sort_test.go b/src/pkg/exp/locale/collate/sort_test.go new file mode 100644 index 0000000000..d0682f48e6 --- /dev/null +++ b/src/pkg/exp/locale/collate/sort_test.go @@ -0,0 +1,52 @@ +// Copyright 2013 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 collate_test + +import ( + "exp/locale/collate" + "fmt" + "testing" +) + +func ExampleCollator_Strings() { + c := collate.New("root") + strings := []string{ + "ad", + "äb", + "ac", + } + c.Strings(strings) + fmt.Println(strings) + // Output: [äb ac ad] +} + +type sorter []string + +func (s sorter) Len() int { + return len(s) +} + +func (s sorter) Swap(i, j int) { + s[j], s[i] = s[i], s[j] +} + +func (s sorter) Bytes(i int) []byte { + return []byte(s[i]) +} + +func TestSort(t *testing.T) { + c := collate.New("en") + strings := []string{ + "bcd", + "abc", + "ddd", + } + c.Sort(sorter(strings)) + res := fmt.Sprint(strings) + want := "[abc bcd ddd]" + if res != want { + t.Errorf("found %s; want %s", res, want) + } +}