diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-09-24 21:46:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-09-24 21:46:21 +0000 |
commit | dd931d9b48647e898dc80927c532ae93cc09e192 (patch) | |
tree | 71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/strings | |
parent | 779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff) | |
download | gcc-dd931d9b48647e898dc80927c532ae93cc09e192.zip gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.gz gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.bz2 |
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435
gotools/:
* Makefile.am (mostlyclean-local): Run chmod on check-go-dir to
make sure it is writable.
(check-go-tools): Likewise.
(check-vet): Copy internal/objabi to check-vet-dir.
* Makefile.in: Rebuild.
From-SVN: r264546
Diffstat (limited to 'libgo/go/strings')
-rw-r--r-- | libgo/go/strings/builder_test.go | 92 | ||||
-rw-r--r-- | libgo/go/strings/compare_test.go | 26 | ||||
-rw-r--r-- | libgo/go/strings/replace.go | 77 | ||||
-rw-r--r-- | libgo/go/strings/search.go | 4 | ||||
-rw-r--r-- | libgo/go/strings/search_test.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/strings.go | 98 | ||||
-rw-r--r-- | libgo/go/strings/strings_amd64.go | 90 | ||||
-rw-r--r-- | libgo/go/strings/strings_decl.go | 2 | ||||
-rw-r--r-- | libgo/go/strings/strings_generic.go | 61 | ||||
-rw-r--r-- | libgo/go/strings/strings_s390x.go | 88 | ||||
-rw-r--r-- | libgo/go/strings/strings_test.go | 12 |
11 files changed, 256 insertions, 296 deletions
diff --git a/libgo/go/strings/builder_test.go b/libgo/go/strings/builder_test.go index ad012bb..da6c021 100644 --- a/libgo/go/strings/builder_test.go +++ b/libgo/go/strings/builder_test.go @@ -85,16 +85,25 @@ func TestBuilderReset(t *testing.T) { } func TestBuilderGrow(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("skip for gccgo until escape analysis improves") + } for _, growLen := range []int{0, 100, 1000, 10000, 100000} { - var b Builder - b.Grow(growLen) p := bytes.Repeat([]byte{'a'}, growLen) - allocs := numAllocs(func() { b.Write(p) }) - if allocs > 0 { - t.Errorf("growLen=%d: allocation occurred during write", growLen) + allocs := testing.AllocsPerRun(100, func() { + var b Builder + b.Grow(growLen) // should be only alloc, when growLen > 0 + b.Write(p) + if b.String() != string(p) { + t.Fatalf("growLen=%d: bad data written after Grow", growLen) + } + }) + wantAllocs := 1 + if growLen == 0 { + wantAllocs = 0 } - if b.String() != string(p) { - t.Errorf("growLen=%d: bad data written after Grow", growLen) + if g, w := int(allocs), wantAllocs; g != w { + t.Errorf("growLen=%d: got %d allocs during Write; want %v", growLen, g, w) } } } @@ -168,16 +177,17 @@ func TestBuilderWriteByte(t *testing.T) { func TestBuilderAllocs(t *testing.T) { if runtime.Compiler == "gccgo" { - t.Skip("skip for gccgo until escape analysis enabled by default") + t.Skip("skip for gccgo until escape analysis improves") } var b Builder - b.Grow(5) + const msg = "hello" + b.Grow(len(msg) * 2) // because AllocsPerRun does an extra "warm-up" iteration var s string - allocs := numAllocs(func() { + allocs := int(testing.AllocsPerRun(1, func() { b.WriteString("hello") s = b.String() - }) - if want := "hello"; s != want { + })) + if want := msg + msg; s != want { t.Errorf("String: got %#q; want %#q", s, want) } if allocs > 0 { @@ -197,15 +207,6 @@ func TestBuilderAllocs(t *testing.T) { } } -func numAllocs(fn func()) uint64 { - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) - var m1, m2 runtime.MemStats - runtime.ReadMemStats(&m1) - fn() - runtime.ReadMemStats(&m2) - return m2.Mallocs - m1.Mallocs -} - func TestBuilderCopyPanic(t *testing.T) { tests := []struct { name string @@ -305,3 +306,52 @@ func TestBuilderCopyPanic(t *testing.T) { } } } + +var someBytes = []byte("some bytes sdljlk jsklj3lkjlk djlkjw") + +var sinkS string + +func benchmarkBuilder(b *testing.B, f func(b *testing.B, numWrite int, grow bool)) { + b.Run("1Write_NoGrow", func(b *testing.B) { + b.ReportAllocs() + f(b, 1, false) + }) + b.Run("3Write_NoGrow", func(b *testing.B) { + b.ReportAllocs() + f(b, 3, false) + }) + b.Run("3Write_Grow", func(b *testing.B) { + b.ReportAllocs() + f(b, 3, true) + }) +} + +func BenchmarkBuildString_Builder(b *testing.B) { + benchmarkBuilder(b, func(b *testing.B, numWrite int, grow bool) { + for i := 0; i < b.N; i++ { + var buf Builder + if grow { + buf.Grow(len(someBytes) * numWrite) + } + for i := 0; i < numWrite; i++ { + buf.Write(someBytes) + } + sinkS = buf.String() + } + }) +} + +func BenchmarkBuildString_ByteBuffer(b *testing.B) { + benchmarkBuilder(b, func(b *testing.B, numWrite int, grow bool) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + if grow { + buf.Grow(len(someBytes) * numWrite) + } + for i := 0; i < numWrite; i++ { + buf.Write(someBytes) + } + sinkS = buf.String() + } + }) +} diff --git a/libgo/go/strings/compare_test.go b/libgo/go/strings/compare_test.go index bc12e42..5d53344 100644 --- a/libgo/go/strings/compare_test.go +++ b/libgo/go/strings/compare_test.go @@ -8,6 +8,7 @@ package strings_test // Benchmarks omitted since the underlying implementation is identical. import ( + "internal/testenv" . "strings" "testing" ) @@ -52,10 +53,21 @@ func TestCompareIdenticalString(t *testing.T) { } func TestCompareStrings(t *testing.T) { - n := 128 + lengths := make([]int, 0) // lengths to test in ascending order + for i := 0; i <= 128; i++ { + lengths = append(lengths, i) + } + lengths = append(lengths, 256, 512, 1024, 1333, 4095, 4096, 4097) + + if !testing.Short() || testenv.Builder() != "" { + lengths = append(lengths, 65535, 65536, 65537, 99999) + } + + n := lengths[len(lengths)-1] a := make([]byte, n+1) b := make([]byte, n+1) - for len := 0; len < 128; len++ { + lastLen := 0 + for _, len := range lengths { // randomish but deterministic data. No 0 or 255. for i := 0; i < len; i++ { a[i] = byte(1 + 31*i%254) @@ -67,21 +79,22 @@ func TestCompareStrings(t *testing.T) { b[i] = 9 } - cmp := Compare(string(a[:len]), string(b[:len])) + sa, sb := string(a), string(b) + cmp := Compare(sa[:len], sb[:len]) if cmp != 0 { t.Errorf(`CompareIdentical(%d) = %d`, len, cmp) } if len > 0 { - cmp = Compare(string(a[:len-1]), string(b[:len])) + cmp = Compare(sa[:len-1], sb[:len]) if cmp != -1 { t.Errorf(`CompareAshorter(%d) = %d`, len, cmp) } - cmp = Compare(string(a[:len]), string(b[:len-1])) + cmp = Compare(sa[:len], sb[:len-1]) if cmp != 1 { t.Errorf(`CompareBshorter(%d) = %d`, len, cmp) } } - for k := 0; k < len; k++ { + for k := lastLen; k < len; k++ { b[k] = a[k] - 1 cmp = Compare(string(a[:len]), string(b[:len])) if cmp != 1 { @@ -94,5 +107,6 @@ func TestCompareStrings(t *testing.T) { } b[k] = a[k] } + lastLen = len } } diff --git a/libgo/go/strings/replace.go b/libgo/go/strings/replace.go index 4752641..58a11a6 100644 --- a/libgo/go/strings/replace.go +++ b/libgo/go/strings/replace.go @@ -18,8 +18,9 @@ type replacer interface { WriteString(w io.Writer, s string) (n int, err error) } -// NewReplacer returns a new Replacer from a list of old, new string pairs. -// Replacements are performed in order, without overlapping matches. +// NewReplacer returns a new Replacer from a list of old, new string +// pairs. Replacements are performed in the order they appear in the +// target string, without overlapping matches. func NewReplacer(oldnew ...string) *Replacer { if len(oldnew)%2 == 1 { panic("strings.NewReplacer: odd argument count") @@ -54,13 +55,21 @@ func NewReplacer(oldnew ...string) *Replacer { return &Replacer{r: &r} } - r := byteStringReplacer{} + r := byteStringReplacer{toReplace: make([]string, 0, len(oldnew)/2)} // The first occurrence of old->new map takes precedence // over the others with the same old string. for i := len(oldnew) - 2; i >= 0; i -= 2 { o := oldnew[i][0] n := oldnew[i+1] - r[o] = []byte(n) + // To avoid counting repetitions multiple times. + if r.replacements[o] == nil { + // We need to use string([]byte{o}) instead of string(o), + // to avoid utf8 encoding of o. + // E. g. byte(150) produces string of length 2. + r.toReplace = append(r.toReplace, string([]byte{o})) + } + r.replacements[o] = []byte(n) + } return &Replacer{r: &r} } @@ -454,34 +463,60 @@ func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) { // byteStringReplacer is the implementation that's used when all the // "old" values are single ASCII bytes but the "new" values vary in size. -// The array contains replacement byte slices indexed by old byte. -// A nil []byte means that the old byte should not be replaced. -type byteStringReplacer [256][]byte +type byteStringReplacer struct { + // replacements contains replacement byte slices indexed by old byte. + // A nil []byte means that the old byte should not be replaced. + replacements [256][]byte + // toReplace keeps a list of bytes to replace. Depending on length of toReplace + // and length of target string it may be faster to use Count, or a plain loop. + // We store single byte as a string, because Count takes a string. + toReplace []string +} + +// countCutOff controls the ratio of a string length to a number of replacements +// at which (*byteStringReplacer).Replace switches algorithms. +// For strings with higher ration of length to replacements than that value, +// we call Count, for each replacement from toReplace. +// For strings, with a lower ratio we use simple loop, because of Count overhead. +// countCutOff is an empirically determined overhead multiplier. +// TODO(tocarip) revisit once we have register-based abi/mid-stack inlining. +const countCutOff = 8 func (r *byteStringReplacer) Replace(s string) string { newSize := len(s) anyChanges := false - for i := 0; i < len(s); i++ { - b := s[i] - if r[b] != nil { - anyChanges = true - // The -1 is because we are replacing 1 byte with len(r[b]) bytes. - newSize += len(r[b]) - 1 + // Is it faster to use Count? + if len(r.toReplace)*countCutOff <= len(s) { + for _, x := range r.toReplace { + if c := Count(s, x); c != 0 { + // The -1 is because we are replacing 1 byte with len(replacements[b]) bytes. + newSize += c * (len(r.replacements[x[0]]) - 1) + anyChanges = true + } + + } + } else { + for i := 0; i < len(s); i++ { + b := s[i] + if r.replacements[b] != nil { + // See above for explanation of -1 + newSize += len(r.replacements[b]) - 1 + anyChanges = true + } } } if !anyChanges { return s } buf := make([]byte, newSize) - bi := buf + j := 0 for i := 0; i < len(s); i++ { b := s[i] - if r[b] != nil { - n := copy(bi, r[b]) - bi = bi[n:] + if r.replacements[b] != nil { + j += copy(buf[j:], r.replacements[b]) } else { - bi[0] = b - bi = bi[1:] + buf[j] = b + j++ } } return string(buf) @@ -492,7 +527,7 @@ func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err erro last := 0 for i := 0; i < len(s); i++ { b := s[i] - if r[b] == nil { + if r.replacements[b] == nil { continue } if last != i { @@ -503,7 +538,7 @@ func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err erro } } last = i + 1 - nw, err := w.Write(r[b]) + nw, err := w.Write(r.replacements[b]) n += nw if err != nil { return n, err diff --git a/libgo/go/strings/search.go b/libgo/go/strings/search.go index f77c879..e5bffbb 100644 --- a/libgo/go/strings/search.go +++ b/libgo/go/strings/search.go @@ -6,8 +6,8 @@ package strings // stringFinder efficiently finds strings in a source text. It's implemented // using the Boyer-Moore string search algorithm: -// http://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm -// http://www.cs.utexas.edu/~moore/publications/fstrpos.pdf (note: this aged +// https://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm +// https://www.cs.utexas.edu/~moore/publications/fstrpos.pdf (note: this aged // document uses 1-based indexing) type stringFinder struct { // pattern is the string that we are searching for in the text. diff --git a/libgo/go/strings/search_test.go b/libgo/go/strings/search_test.go index 966c05e..c01a393 100644 --- a/libgo/go/strings/search_test.go +++ b/libgo/go/strings/search_test.go @@ -57,7 +57,7 @@ func TestFinderCreation(t *testing.T) { [256]int{'i': 3, 'm': 7, 's': 1}, []int{15, 14, 13, 7, 11, 10, 7, 1}, }, - // From http://www.cs.utexas.edu/~moore/publications/fstrpos.pdf + // From https://www.cs.utexas.edu/~moore/publications/fstrpos.pdf { "abcxxxabc", [256]int{'a': 2, 'b': 1, 'c': 6, 'x': 3}, diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go index 05e8243..20868be 100644 --- a/libgo/go/strings/strings.go +++ b/libgo/go/strings/strings.go @@ -8,6 +8,7 @@ package strings import ( + "internal/bytealg" "unicode" "unicode/utf8" ) @@ -72,12 +73,16 @@ func hashStrRev(sep string) (uint32, uint32) { return hash, pow } -// countGeneric implements Count. -func countGeneric(s, substr string) int { +// Count counts the number of non-overlapping instances of substr in s. +// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. +func Count(s, substr string) int { // special case if len(substr) == 0 { return utf8.RuneCountInString(s) + 1 } + if len(substr) == 1 { + return bytealg.CountString(s, substr[0]) + } n := 0 for { i := Index(s, substr) @@ -792,6 +797,8 @@ func Trim(s string, cutset string) string { // TrimLeft returns a slice of the string s with all leading // Unicode code points contained in cutset removed. +// +// To remove a prefix, use TrimPrefix instead. func TrimLeft(s string, cutset string) string { if s == "" || cutset == "" { return s @@ -801,6 +808,8 @@ func TrimLeft(s string, cutset string) string { // TrimRight returns a slice of the string s, with all trailing // Unicode code points contained in cutset removed. +// +// To remove a suffix, use TrimSuffix instead. func TrimRight(s string, cutset string) string { if s == "" || cutset == "" { return s @@ -903,9 +912,9 @@ func EqualFold(s, t string) bool { tr, sr = sr, tr } // Fast check for ASCII. - if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' { - // ASCII, and sr is upper case. tr must be lower case. - if tr == sr+'a'-'A' { + if tr < utf8.RuneSelf { + // ASCII only, sr/tr must be upper/lower case + if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { continue } return false @@ -927,6 +936,85 @@ func EqualFold(s, t string) bool { return s == t } +// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. +func Index(s, substr string) int { + n := len(substr) + switch { + case n == 0: + return 0 + case n == 1: + return IndexByte(s, substr[0]) + case n == len(s): + if substr == s { + return 0 + } + return -1 + case n > len(s): + return -1 + case n <= bytealg.MaxLen: + // Use brute force when s and substr both are small + if len(s) <= bytealg.MaxBruteForce { + return bytealg.IndexString(s, substr) + } + c := substr[0] + i := 0 + t := s[:len(s)-n+1] + fails := 0 + for i < len(t) { + if t[i] != c { + // IndexByte is faster than bytealg.IndexString, so use it as long as + // we're not getting lots of false positives. + o := IndexByte(t[i:], c) + if o < 0 { + return -1 + } + i += o + } + if s[i:i+n] == substr { + return i + } + fails++ + i++ + // Switch to bytealg.IndexString when IndexByte produces too many false positives. + if fails > bytealg.Cutover(i) { + r := bytealg.IndexString(s[i:], substr) + if r >= 0 { + return r + i + } + return -1 + } + } + return -1 + } + c := substr[0] + i := 0 + t := s[:len(s)-n+1] + fails := 0 + for i < len(t) { + if t[i] != c { + o := IndexByte(t[i:], c) + if o < 0 { + return -1 + } + i += o + } + if s[i:i+n] == substr { + return i + } + i++ + fails++ + if fails >= 4+i>>4 && i < len(t) { + // See comment in ../bytes/bytes_generic.go. + j := indexRabinKarp(s[i:], substr) + if j < 0 { + return -1 + } + return i + j + } + } + return -1 +} + func indexRabinKarp(s, substr string) int { // Rabin-Karp search hashss, pow := hashStr(substr) diff --git a/libgo/go/strings/strings_amd64.go b/libgo/go/strings/strings_amd64.go deleted file mode 100644 index 2441569..0000000 --- a/libgo/go/strings/strings_amd64.go +++ /dev/null @@ -1,90 +0,0 @@ -// 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. - -// +build ignore - -package strings - -import "internal/cpu" - -//go:noescape - -// indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s. -// indexShortStr requires 2 <= len(c) <= shortStringLen -func indexShortStr(s, c string) int // ../runtime/asm_amd64.s -func countByte(s string, c byte) int // ../runtime/asm_amd64.s - -var shortStringLen int - -func init() { - if cpu.X86.HasAVX2 { - shortStringLen = 63 - } else { - shortStringLen = 31 - } -} - -// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. -func Index(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return 0 - case n == 1: - return IndexByte(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - case n <= shortStringLen: - // Use brute force when s and substr both are small - if len(s) <= 64 { - return indexShortStr(s, substr) - } - c := substr[0] - i := 0 - t := s[:len(s)-n+1] - fails := 0 - for i < len(t) { - if t[i] != c { - // IndexByte skips 16/32 bytes per iteration, - // so it's faster than indexShortStr. - o := IndexByte(t[i:], c) - if o < 0 { - return -1 - } - i += o - } - if s[i:i+n] == substr { - return i - } - fails++ - i++ - // Switch to indexShortStr when IndexByte produces too many false positives. - // Too many means more that 1 error per 8 characters. - // Allow some errors in the beginning. - if fails > (i+16)/8 { - r := indexShortStr(s[i:], substr) - if r >= 0 { - return r + i - } - return -1 - } - } - return -1 - } - return indexRabinKarp(s, substr) -} - -// Count counts the number of non-overlapping instances of substr in s. -// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. -func Count(s, substr string) int { - if len(substr) == 1 && cpu.X86.HasPOPCNT { - return countByte(s, byte(substr[0])) - } - return countGeneric(s, substr) -} diff --git a/libgo/go/strings/strings_decl.go b/libgo/go/strings/strings_decl.go index 3bae844..9819444 100644 --- a/libgo/go/strings/strings_decl.go +++ b/libgo/go/strings/strings_decl.go @@ -5,4 +5,4 @@ package strings // IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s. -func IndexByte(s string, c byte) int // ../runtime/asm_$GOARCH.s +func IndexByte(s string, c byte) int // in internal/bytealg diff --git a/libgo/go/strings/strings_generic.go b/libgo/go/strings/strings_generic.go deleted file mode 100644 index 60a6f78..0000000 --- a/libgo/go/strings/strings_generic.go +++ /dev/null @@ -1,61 +0,0 @@ -// 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. - -// -build !amd64,!s390x - -package strings - -// TODO: implements short string optimization on non amd64 platforms -// and get rid of strings_amd64.go - -// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. -func Index(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return 0 - case n == 1: - return IndexByte(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - } - c := substr[0] - i := 0 - t := s[:len(s)-n+1] - fails := 0 - for i < len(t) { - if t[i] != c { - o := IndexByte(t[i:], c) - if o < 0 { - return -1 - } - i += o - } - if s[i:i+n] == substr { - return i - } - i++ - fails++ - if fails >= 4+i>>4 && i < len(t) { - // See comment in ../bytes/bytes_generic.go. - j := indexRabinKarp(s[i:], substr) - if j < 0 { - return -1 - } - return i + j - } - } - return -1 -} - -// Count counts the number of non-overlapping instances of substr in s. -// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. -func Count(s, substr string) int { - return countGeneric(s, substr) -} diff --git a/libgo/go/strings/strings_s390x.go b/libgo/go/strings/strings_s390x.go deleted file mode 100644 index e74e4cd..0000000 --- a/libgo/go/strings/strings_s390x.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2016 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. - -// +build ignore - -package strings - -//go:noescape - -// indexShortStr returns the index of the first instance of sep in s, -// or -1 if sep is not present in s. -// indexShortStr requires 2 <= len(sep) <= shortStringLen -func indexShortStr(s, sep string) int // ../runtime/asm_$GOARCH.s - -// supportsVX reports whether the vector facility is available. -// indexShortStr must not be called if the vector facility is not -// available. -func supportsVX() bool // ../runtime/asm_s390x.s - -var shortStringLen = -1 - -func init() { - if supportsVX() { - shortStringLen = 64 - } -} - -// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. -func Index(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return 0 - case n == 1: - return IndexByte(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - case n <= shortStringLen: - // Use brute force when s and substr both are small - if len(s) <= 64 { - return indexShortStr(s, substr) - } - c := substr[0] - i := 0 - t := s[:len(s)-n+1] - fails := 0 - for i < len(t) { - if t[i] != c { - // IndexByte skips 16/32 bytes per iteration, - // so it's faster than indexShortStr. - o := IndexByte(t[i:], c) - if o < 0 { - return -1 - } - i += o - } - if s[i:i+n] == substr { - return i - } - fails++ - i++ - // Switch to indexShortStr when IndexByte produces too many false positives. - // Too many means more that 1 error per 8 characters. - // Allow some errors in the beginning. - if fails > (i+16)/8 { - r := indexShortStr(s[i:], substr) - if r >= 0 { - return r + i - } - return -1 - } - } - return -1 - } - return indexRabinKarp(s, substr) -} - -// Count counts the number of non-overlapping instances of substr in s. -// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. -func Count(s, substr string) int { - return countGeneric(s, substr) -} diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index 92122db..3f0c790 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -1406,6 +1406,8 @@ var EqualFoldTests = []struct { {"abcdefghijK", "abcdefghij\u212A", true}, {"abcdefghijkz", "abcdefghij\u212Ay", false}, {"abcdefghijKz", "abcdefghij\u212Ay", false}, + {"1", "2", false}, + {"utf-8", "US-ASCII", false}, } func TestEqualFold(t *testing.T) { @@ -1419,6 +1421,16 @@ func TestEqualFold(t *testing.T) { } } +func BenchmarkEqualFold(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tt := range EqualFoldTests { + if out := EqualFold(tt.s, tt.t); out != tt.out { + b.Fatal("wrong result") + } + } + } +} + var CountTests = []struct { s, sep string num int |