diff options
Diffstat (limited to 'libgo/go/strings')
-rw-r--r-- | libgo/go/strings/compare.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/compare_test.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/reader.go | 20 | ||||
-rw-r--r-- | libgo/go/strings/reader_test.go | 46 | ||||
-rw-r--r-- | libgo/go/strings/strings.go | 37 | ||||
-rw-r--r-- | libgo/go/strings/strings_amd64.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/strings_decl.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/strings_generic.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/strings_test.go | 142 |
9 files changed, 174 insertions, 81 deletions
diff --git a/libgo/go/strings/compare.go b/libgo/go/strings/compare.go index b84dddea74e..1fe6b8d89a3 100644 --- a/libgo/go/strings/compare.go +++ b/libgo/go/strings/compare.go @@ -1,4 +1,4 @@ -// Copyright 2015 The Go Authors. All rights reserved. +// Copyright 2015 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. diff --git a/libgo/go/strings/compare_test.go b/libgo/go/strings/compare_test.go index 68fc88e1431..bc12e421b0d 100644 --- a/libgo/go/strings/compare_test.go +++ b/libgo/go/strings/compare_test.go @@ -56,7 +56,7 @@ func TestCompareStrings(t *testing.T) { a := make([]byte, n+1) b := make([]byte, n+1) for len := 0; len < 128; len++ { - // randomish but deterministic data. No 0 or 255. + // randomish but deterministic data. No 0 or 255. for i := 0; i < len; i++ { a[i] = byte(1 + 31*i%254) b[i] = byte(1 + 31*i%254) diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go index 7a872fbcb08..6c1a5064c0d 100644 --- a/libgo/go/strings/reader.go +++ b/libgo/go/strings/reader.go @@ -35,9 +35,6 @@ func (r *Reader) Len() int { func (r *Reader) Size() int64 { return int64(len(r.s)) } func (r *Reader) Read(b []byte) (n int, err error) { - if len(b) == 0 { - return 0, nil - } if r.i >= int64(len(r.s)) { return 0, io.EOF } @@ -62,14 +59,14 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { return } -func (r *Reader) ReadByte() (b byte, err error) { +func (r *Reader) ReadByte() (byte, error) { r.prevRune = -1 if r.i >= int64(len(r.s)) { return 0, io.EOF } - b = r.s[r.i] + b := r.s[r.i] r.i++ - return + return b, nil } func (r *Reader) UnreadByte() error { @@ -110,11 +107,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { r.prevRune = -1 var abs int64 switch whence { - case 0: + case io.SeekStart: abs = offset - case 1: - abs = int64(r.i) + offset - case 2: + case io.SeekCurrent: + abs = r.i + offset + case io.SeekEnd: abs = int64(len(r.s)) + offset default: return 0, errors.New("strings.Reader.Seek: invalid whence") @@ -145,6 +142,9 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { return } +// Reset resets the Reader to be reading from s. +func (r *Reader) Reset(s string) { *r = Reader{s, 0, -1} } + // NewReader returns a new Reader reading from s. // It is similar to bytes.NewBufferString but more efficient and read-only. func NewReader(s string) *Reader { return &Reader{s, 0, -1} } diff --git a/libgo/go/strings/reader_test.go b/libgo/go/strings/reader_test.go index 5003a37be48..bf40eb1a31e 100644 --- a/libgo/go/strings/reader_test.go +++ b/libgo/go/strings/reader_test.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "io/ioutil" - "os" "strings" "sync" "testing" @@ -23,17 +22,18 @@ func TestReader(t *testing.T) { n int want string wantpos int64 + readerr error seekerr string }{ - {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"}, - {seek: os.SEEK_SET, off: 1, n: 1, want: "1"}, - {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"}, - {seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"}, - {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33}, - {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1}, - {seek: os.SEEK_SET, n: 5, want: "01234"}, - {seek: os.SEEK_CUR, n: 5, want: "56789"}, - {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"}, + {seek: io.SeekStart, off: 0, n: 20, want: "0123456789"}, + {seek: io.SeekStart, off: 1, n: 1, want: "1"}, + {seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"}, + {seek: io.SeekStart, off: -1, seekerr: "strings.Reader.Seek: negative position"}, + {seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF}, + {seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF}, + {seek: io.SeekStart, n: 5, want: "01234"}, + {seek: io.SeekCurrent, n: 5, want: "56789"}, + {seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"}, } for i, tt := range tests { @@ -51,8 +51,8 @@ func TestReader(t *testing.T) { } buf := make([]byte, tt.n) n, err := r.Read(buf) - if err != nil { - t.Errorf("%d. read = %v", i, err) + if err != tt.readerr { + t.Errorf("%d. read = %v; want %v", i, err, tt.readerr) continue } got := string(buf[:n]) @@ -64,7 +64,7 @@ func TestReader(t *testing.T) { func TestReadAfterBigSeek(t *testing.T) { r := strings.NewReader("0123456789") - if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil { + if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil { t.Fatal(err) } if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF { @@ -170,3 +170,23 @@ func TestReaderLenSize(t *testing.T) { t.Errorf("Size = %d; want 3", r.Size()) } } + +func TestReaderReset(t *testing.T) { + r := strings.NewReader("世界") + if _, _, err := r.ReadRune(); err != nil { + t.Errorf("ReadRune: unexpected error: %v", err) + } + + const want = "abcdef" + r.Reset(want) + if err := r.UnreadRune(); err == nil { + t.Errorf("UnreadRune: expected error, got nil") + } + buf, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("ReadAll: unexpected error: %v", err) + } + if got := string(buf); got != want { + t.Errorf("ReadAll: got %q, want %q", got, want) + } +} diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go index 37d5647ffd6..919e8c8354e 100644 --- a/libgo/go/strings/strings.go +++ b/libgo/go/strings/strings.go @@ -12,32 +12,25 @@ import ( "unicode/utf8" ) -// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit). -// Invalid UTF-8 sequences become correct encodings of U+FFF8. +// explode splits s into a slice of UTF-8 strings, +// one string per Unicode character up to a maximum of n (n < 0 means no limit). +// Invalid UTF-8 sequences become correct encodings of U+FFFD. func explode(s string, n int) []string { - if n == 0 { - return nil - } l := utf8.RuneCountInString(s) - if n <= 0 || n > l { + if n < 0 || n > l { n = l } a := make([]string, n) - var size int - var ch rune - i, cur := 0, 0 - for ; i+1 < n; i++ { - ch, size = utf8.DecodeRuneInString(s[cur:]) + for i := 0; i < n-1; i++ { + ch, size := utf8.DecodeRuneInString(s) + a[i] = s[:size] + s = s[size:] if ch == utf8.RuneError { a[i] = string(utf8.RuneError) - } else { - a[i] = s[cur : cur+size] } - cur += size } - // add the rest, if there is any - if cur < len(s) { - a[i] = s[cur:] + if n > 0 { + a[n-1] = s } return a } @@ -346,7 +339,7 @@ func FieldsFunc(s string, f func(rune) bool) []string { return a } -// Join concatenates the elements of a to create a single string. The separator string +// Join concatenates the elements of a to create a single string. The separator string // sep is placed between elements in the resulting string. func Join(a []string, sep string) string { if len(a) == 0 { @@ -384,8 +377,8 @@ func HasSuffix(s, suffix string) bool { // dropped from the string with no replacement. func Map(mapping func(rune) rune, s string) string { // In the worst case, the string can grow when mapped, making - // things unpleasant. But it's so rare we barge in assuming it's - // fine. It could also shrink but that falls out naturally. + // things unpleasant. But it's so rare we barge in assuming it's + // fine. It could also shrink but that falls out naturally. maxbytes := len(s) // length of b nbytes := 0 // number of bytes encoded in b // The output buffer b is initialized on demand, the first @@ -714,7 +707,7 @@ func EqualFold(s, t string) bool { return false } - // General case. SimpleFold(x) returns the next equivalent rune > x + // General case. SimpleFold(x) returns the next equivalent rune > x // or wraps around to smaller values. r := unicode.SimpleFold(sr) for r != sr && r < tr { @@ -726,6 +719,6 @@ func EqualFold(s, t string) bool { return false } - // One string is empty. Are both? + // One string is empty. Are both? return s == t } diff --git a/libgo/go/strings/strings_amd64.go b/libgo/go/strings/strings_amd64.go index 376113f0a22..55bf2d2f6fc 100644 --- a/libgo/go/strings/strings_amd64.go +++ b/libgo/go/strings/strings_amd64.go @@ -1,4 +1,4 @@ -// Copyright 2015 The Go Authors. All rights reserved. +// Copyright 2015 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. diff --git a/libgo/go/strings/strings_decl.go b/libgo/go/strings/strings_decl.go index 810a696af27..3bae8448c3d 100644 --- a/libgo/go/strings/strings_decl.go +++ b/libgo/go/strings/strings_decl.go @@ -1,4 +1,4 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// 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. diff --git a/libgo/go/strings/strings_generic.go b/libgo/go/strings/strings_generic.go index 811cb803168..d356f50f877 100644 --- a/libgo/go/strings/strings_generic.go +++ b/libgo/go/strings/strings_generic.go @@ -1,4 +1,4 @@ -// Copyright 2015 The Go Authors. All rights reserved. +// Copyright 2015 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. diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index 49f55fe38c7..fcef761da79 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -190,6 +190,43 @@ func TestLastIndexByte(t *testing.T) { } } +func simpleIndex(s, sep string) int { + n := len(sep) + for i := n; i <= len(s); i++ { + if s[i-n:i] == sep { + return i - n + } + } + return -1 +} + +func TestIndexRandom(t *testing.T) { + const chars = "abcdefghijklmnopqrstuvwxyz0123456789" + for times := 0; times < 10; times++ { + for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary + s1 := make([]byte, strLen) + for i := range s1 { + s1[i] = chars[rand.Intn(len(chars))] + } + s := string(s1) + for i := 0; i < 50; i++ { + begin := rand.Intn(len(s) + 1) + end := begin + rand.Intn(len(s)+1-begin) + sep := s[begin:end] + if i%4 == 0 { + pos := rand.Intn(len(sep) + 1) + sep = sep[:pos] + "A" + sep[pos:] + } + want := simpleIndex(s, sep) + res := Index(s, sep) + if res != want { + t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want) + } + } + } + } +} + var indexRuneTests = []struct { s string rune rune @@ -256,31 +293,6 @@ func BenchmarkIndexByte(b *testing.B) { } } -var explodetests = []struct { - s string - n int - a []string -}{ - {"", -1, []string{}}, - {abcd, 4, []string{"a", "b", "c", "d"}}, - {faces, 3, []string{"☺", "☻", "☹"}}, - {abcd, 2, []string{"a", "bcd"}}, -} - -func TestExplode(t *testing.T) { - for _, tt := range explodetests { - a := SplitN(tt.s, "", tt.n) - if !eq(a, tt.a) { - t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a) - continue - } - s := Join(a, "") - if s != tt.s { - t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s) - } - } -} - type SplitTest struct { s string sep string @@ -289,19 +301,23 @@ type SplitTest struct { } var splittests = []SplitTest{ + {"", "", -1, []string{}}, + {abcd, "", 2, []string{"a", "bcd"}}, + {abcd, "", 4, []string{"a", "b", "c", "d"}}, + {abcd, "", -1, []string{"a", "b", "c", "d"}}, + {faces, "", -1, []string{"☺", "☻", "☹"}}, + {faces, "", 3, []string{"☺", "☻", "☹"}}, + {faces, "", 17, []string{"☺", "☻", "☹"}}, + {"☺�☹", "", -1, []string{"☺", "�", "☹"}}, {abcd, "a", 0, nil}, {abcd, "a", -1, []string{"", "bcd"}}, {abcd, "z", -1, []string{"abcd"}}, - {abcd, "", -1, []string{"a", "b", "c", "d"}}, {commas, ",", -1, []string{"1", "2", "3", "4"}}, {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, {faces, "☹", -1, []string{"☺☻", ""}}, {faces, "~", -1, []string{faces}}, - {faces, "", -1, []string{"☺", "☻", "☹"}}, {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, {"1 2", " ", 3, []string{"1", "2"}}, - {"123", "", 2, []string{"1", "23"}}, - {"123", "", 17, []string{"1", "2", "3"}}, } func TestSplit(t *testing.T) { @@ -492,7 +508,7 @@ func rot13(r rune) rune { func TestMap(t *testing.T) { // Run a couple of awful growth/shrinkage tests a := tenRunes('a') - // 1. Grow. This triggers two reallocations in Map. + // 1. Grow. This triggers two reallocations in Map. maxRune := func(rune) rune { return unicode.MaxRune } m := Map(maxRune, a) expect := tenRunes(unicode.MaxRune) @@ -973,7 +989,7 @@ var UnreadRuneErrorTests = []struct { {"Read", func(r *Reader) { r.Read([]byte{0}) }}, {"ReadByte", func(r *Reader) { r.ReadByte() }}, {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, - {"Seek", func(r *Reader) { r.Seek(0, 1) }}, + {"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }}, {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }}, } @@ -1057,6 +1073,70 @@ var ContainsTests = []struct { {"abc", "bcd", false}, {"abc", "", true}, {"", "a", false}, + + // cases to cover code in runtime/asm_amd64.s:indexShortStr + // 2-byte needle + {"xxxxxx", "01", false}, + {"01xxxx", "01", true}, + {"xx01xx", "01", true}, + {"xxxx01", "01", true}, + {"01xxxxx"[1:], "01", false}, + {"xxxxx01"[:6], "01", false}, + // 3-byte needle + {"xxxxxxx", "012", false}, + {"012xxxx", "012", true}, + {"xx012xx", "012", true}, + {"xxxx012", "012", true}, + {"012xxxxx"[1:], "012", false}, + {"xxxxx012"[:7], "012", false}, + // 4-byte needle + {"xxxxxxxx", "0123", false}, + {"0123xxxx", "0123", true}, + {"xx0123xx", "0123", true}, + {"xxxx0123", "0123", true}, + {"0123xxxxx"[1:], "0123", false}, + {"xxxxx0123"[:8], "0123", false}, + // 5-7-byte needle + {"xxxxxxxxx", "01234", false}, + {"01234xxxx", "01234", true}, + {"xx01234xx", "01234", true}, + {"xxxx01234", "01234", true}, + {"01234xxxxx"[1:], "01234", false}, + {"xxxxx01234"[:9], "01234", false}, + // 8-byte needle + {"xxxxxxxxxxxx", "01234567", false}, + {"01234567xxxx", "01234567", true}, + {"xx01234567xx", "01234567", true}, + {"xxxx01234567", "01234567", true}, + {"01234567xxxxx"[1:], "01234567", false}, + {"xxxxx01234567"[:12], "01234567", false}, + // 9-15-byte needle + {"xxxxxxxxxxxxx", "012345678", false}, + {"012345678xxxx", "012345678", true}, + {"xx012345678xx", "012345678", true}, + {"xxxx012345678", "012345678", true}, + {"012345678xxxxx"[1:], "012345678", false}, + {"xxxxx012345678"[:13], "012345678", false}, + // 16-byte needle + {"xxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEF", false}, + {"0123456789ABCDEFxxxx", "0123456789ABCDEF", true}, + {"xx0123456789ABCDEFxx", "0123456789ABCDEF", true}, + {"xxxx0123456789ABCDEF", "0123456789ABCDEF", true}, + {"0123456789ABCDEFxxxxx"[1:], "0123456789ABCDEF", false}, + {"xxxxx0123456789ABCDEF"[:20], "0123456789ABCDEF", false}, + // 17-31-byte needle + {"xxxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEFG", false}, + {"0123456789ABCDEFGxxxx", "0123456789ABCDEFG", true}, + {"xx0123456789ABCDEFGxx", "0123456789ABCDEFG", true}, + {"xxxx0123456789ABCDEFG", "0123456789ABCDEFG", true}, + {"0123456789ABCDEFGxxxxx"[1:], "0123456789ABCDEFG", false}, + {"xxxxx0123456789ABCDEFG"[:21], "0123456789ABCDEFG", false}, + + // partial match cases + {"xx01x", "012", false}, // 3 + {"xx0123x", "01234", false}, // 5-7 + {"xx01234567x", "012345678", false}, // 9-15 + {"xx0123456789ABCDEFx", "0123456789ABCDEFG", false}, // 17-31, issue 15679 } func TestContains(t *testing.T) { |