summaryrefslogtreecommitdiff
path: root/libgo/go/strings
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/strings')
-rw-r--r--libgo/go/strings/compare.go2
-rw-r--r--libgo/go/strings/compare_test.go2
-rw-r--r--libgo/go/strings/reader.go20
-rw-r--r--libgo/go/strings/reader_test.go46
-rw-r--r--libgo/go/strings/strings.go37
-rw-r--r--libgo/go/strings/strings_amd64.go2
-rw-r--r--libgo/go/strings/strings_decl.go2
-rw-r--r--libgo/go/strings/strings_generic.go2
-rw-r--r--libgo/go/strings/strings_test.go142
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) {