diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-16 15:47:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-16 15:47:21 +0000 |
commit | adb0401dac41c81571722312d4586b2693f95aa6 (patch) | |
tree | ea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/go/strings | |
parent | 5548ca3540bccbc908a45942896d635ea5f1c23f (diff) | |
download | gcc-adb0401dac41c81571722312d4586b2693f95aa6.zip gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.gz gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.bz2 |
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo/go/strings')
-rw-r--r-- | libgo/go/strings/reader.go | 74 | ||||
-rw-r--r-- | libgo/go/strings/strings.go | 27 | ||||
-rw-r--r-- | libgo/go/strings/strings_test.go | 89 |
3 files changed, 153 insertions, 37 deletions
diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go index 914faa0..eb515de 100644 --- a/libgo/go/strings/reader.go +++ b/libgo/go/strings/reader.go @@ -9,53 +9,83 @@ import ( "utf8" ) -// A Reader satisfies calls to Read, ReadByte, and ReadRune by -// reading from a string. -type Reader string +// A Reader implements the io.Reader, io.ByteScanner, and +// io.RuneScanner interfaces by reading from a string. +type Reader struct { + s string + i int // current reading index + prevRune int // index of previous rune; or < 0 +} + +// Len returns the number of bytes of the unread portion of the +// string. +func (r *Reader) Len() int { + return len(r.s) - r.i +} func (r *Reader) Read(b []byte) (n int, err os.Error) { - s := *r - if len(s) == 0 { + if r.i >= len(r.s) { return 0, os.EOF } - for n < len(s) && n < len(b) { - b[n] = s[n] - n++ - } - *r = s[n:] + n = copy(b, r.s[r.i:]) + r.i += n + r.prevRune = -1 return } func (r *Reader) ReadByte() (b byte, err os.Error) { - s := *r - if len(s) == 0 { + if r.i >= len(r.s) { return 0, os.EOF } - b = s[0] - *r = s[1:] + b = r.s[r.i] + r.i++ + r.prevRune = -1 return } +// UnreadByte moves the reading position back by one byte. +// It is an error to call UnreadByte if nothing has been +// read yet. +func (r *Reader) UnreadByte() os.Error { + if r.i <= 0 { + return os.NewError("strings.Reader: at beginning of string") + } + r.i-- + r.prevRune = -1 + return nil +} + // ReadRune reads and returns the next UTF-8-encoded // Unicode code point from the buffer. // If no bytes are available, the error returned is os.EOF. // If the bytes are an erroneous UTF-8 encoding, it // consumes one byte and returns U+FFFD, 1. func (r *Reader) ReadRune() (rune int, size int, err os.Error) { - s := *r - if len(s) == 0 { + if r.i >= len(r.s) { return 0, 0, os.EOF } - c := s[0] - if c < utf8.RuneSelf { - *r = s[1:] + r.prevRune = r.i + if c := r.s[r.i]; c < utf8.RuneSelf { + r.i++ return int(c), 1, nil } - rune, size = utf8.DecodeRuneInString(string(s)) - *r = s[size:] + rune, size = utf8.DecodeRuneInString(r.s[r.i:]) + r.i += size return } +// UnreadRune causes the next call to ReadRune to return the same rune +// as the previous call to ReadRune. +// The last method called on r must have been ReadRune. +func (r *Reader) UnreadRune() os.Error { + if r.prevRune < 0 { + return os.NewError("strings.Reader: previous operation was not ReadRune") + } + r.i = r.prevRune + r.prevRune = -1 + return nil +} + // 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) } +func NewReader(s string) *Reader { return &Reader{s, 0, -1} } diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go index bfd0571..c547297 100644 --- a/libgo/go/strings/strings.go +++ b/libgo/go/strings/strings.go @@ -198,26 +198,40 @@ func genSplit(s, sep string, sepSave, n int) []string { return a[0 : na+1] } -// Split slices s into substrings separated by sep and returns a slice of +// SplitN slices s into substrings separated by sep and returns a slice of // the substrings between those separators. -// If sep is empty, Split splits after each UTF-8 sequence. +// If sep is empty, SplitN splits after each UTF-8 sequence. // The count determines the number of substrings to return: // n > 0: at most n substrings; the last substring will be the unsplit remainder. // n == 0: the result is nil (zero substrings) // n < 0: all substrings -func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } +func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } -// SplitAfter slices s into substrings after each instance of sep and +// SplitAfterN slices s into substrings after each instance of sep and // returns a slice of those substrings. -// If sep is empty, Split splits after each UTF-8 sequence. +// If sep is empty, SplitAfterN splits after each UTF-8 sequence. // The count determines the number of substrings to return: // n > 0: at most n substrings; the last substring will be the unsplit remainder. // n == 0: the result is nil (zero substrings) // n < 0: all substrings -func SplitAfter(s, sep string, n int) []string { +func SplitAfterN(s, sep string, n int) []string { return genSplit(s, sep, len(sep), n) } +// Split slices s into all substrings separated by sep and returns a slice of +// the substrings between those separators. +// If sep is empty, Split splits after each UTF-8 sequence. +// It is equivalent to SplitN with a count of -1. +func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } + +// SplitAfter slices s into all substrings after each instance of sep and +// returns a slice of those substrings. +// If sep is empty, SplitAfter splits after each UTF-8 sequence. +// It is equivalent to SplitAfterN with a count of -1. +func SplitAfter(s, sep string) []string { + return genSplit(s, sep, len(sep), -1) +} + // Fields splits the string s around each instance of one or more consecutive white space // characters, returning an array of substrings of s or an empty list if s contains only white space. func Fields(s string) []string { @@ -349,7 +363,6 @@ func Repeat(s string, count int) string { return string(b) } - // ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case. func ToUpper(s string) string { return Map(unicode.ToUpper, s) } diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index c45b148..409d4da 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -5,6 +5,7 @@ package strings_test import ( + "bytes" "os" "reflect" "strconv" @@ -169,7 +170,6 @@ func BenchmarkIndex(b *testing.B) { } } - type ExplodeTest struct { s string n int @@ -185,7 +185,7 @@ var explodetests = []ExplodeTest{ func TestExplode(t *testing.T) { for _, tt := range explodetests { - a := Split(tt.s, "", tt.n) + 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 @@ -222,7 +222,7 @@ var splittests = []SplitTest{ func TestSplit(t *testing.T) { for _, tt := range splittests { - a := Split(tt.s, tt.sep, tt.n) + a := SplitN(tt.s, tt.sep, tt.n) if !eq(a, tt.a) { t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a) continue @@ -234,6 +234,12 @@ func TestSplit(t *testing.T) { if s != tt.s { t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s) } + if tt.n < 0 { + b := Split(tt.s, tt.sep) + if !reflect.DeepEqual(a, b) { + t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } } } @@ -255,7 +261,7 @@ var splitaftertests = []SplitTest{ func TestSplitAfter(t *testing.T) { for _, tt := range splitaftertests { - a := SplitAfter(tt.s, tt.sep, tt.n) + a := SplitAfterN(tt.s, tt.sep, tt.n) if !eq(a, tt.a) { t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a) continue @@ -264,6 +270,12 @@ func TestSplitAfter(t *testing.T) { if s != tt.s { t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) } + if tt.n < 0 { + b := SplitAfter(tt.s, tt.sep) + if !reflect.DeepEqual(a, b) { + t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } } } @@ -312,7 +324,6 @@ func TestFieldsFunc(t *testing.T) { } } - // Test case for any function which accepts and returns a single string. type StringTest struct { in, out string @@ -622,8 +633,8 @@ func equal(m string, s1, s2 string, t *testing.T) bool { if s1 == s2 { return true } - e1 := Split(s1, "", -1) - e2 := Split(s2, "", -1) + e1 := Split(s1, "") + e2 := Split(s2, "") for i, c1 := range e1 { if i > len(e2) { break @@ -751,13 +762,56 @@ func TestRunes(t *testing.T) { } } +func TestReadByte(t *testing.T) { + testStrings := []string{"", abcd, faces, commas} + for _, s := range testStrings { + reader := NewReader(s) + if e := reader.UnreadByte(); e == nil { + t.Errorf("Unreading %q at beginning: expected error", s) + } + var res bytes.Buffer + for { + b, e := reader.ReadByte() + if e == os.EOF { + break + } + if e != nil { + t.Errorf("Reading %q: %s", s, e) + break + } + res.WriteByte(b) + // unread and read again + e = reader.UnreadByte() + if e != nil { + t.Errorf("Unreading %q: %s", s, e) + break + } + b1, e := reader.ReadByte() + if e != nil { + t.Errorf("Reading %q after unreading: %s", s, e) + break + } + if b1 != b { + t.Errorf("Reading %q after unreading: want byte %q, got %q", s, b, b1) + break + } + } + if res.String() != s { + t.Errorf("Reader(%q).ReadByte() produced %q", s, res.String()) + } + } +} + func TestReadRune(t *testing.T) { testStrings := []string{"", abcd, faces, commas} for _, s := range testStrings { reader := NewReader(s) + if e := reader.UnreadRune(); e == nil { + t.Errorf("Unreading %q at beginning: expected error", s) + } res := "" for { - r, _, e := reader.ReadRune() + r, z, e := reader.ReadRune() if e == os.EOF { break } @@ -766,6 +820,25 @@ func TestReadRune(t *testing.T) { break } res += string(r) + // unread and read again + e = reader.UnreadRune() + if e != nil { + t.Errorf("Unreading %q: %s", s, e) + break + } + r1, z1, e := reader.ReadRune() + if e != nil { + t.Errorf("Reading %q after unreading: %s", s, e) + break + } + if r1 != r { + t.Errorf("Reading %q after unreading: want rune %q, got %q", s, r, r1) + break + } + if z1 != z { + t.Errorf("Reading %q after unreading: want size %d, got %d", s, z, z1) + break + } } if res != s { t.Errorf("Reader(%q).ReadRune() produced %q", s, res) |