aboutsummaryrefslogtreecommitdiff
path: root/src/strings
diff options
context:
space:
mode:
Diffstat (limited to 'src/strings')
-rw-r--r--src/strings/strings.go44
-rw-r--r--src/strings/strings_test.go54
2 files changed, 86 insertions, 12 deletions
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 7fb05b7d0e..2789f5fb25 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -143,6 +143,14 @@ func IndexAny(s, chars string) int {
// Avoid scanning all of s.
return -1
}
+ if len(chars) == 1 {
+ // Avoid scanning all of s.
+ r := rune(chars[0])
+ if r >= utf8.RuneSelf {
+ r = utf8.RuneError
+ }
+ return IndexRune(s, r)
+ }
if len(s) > 8 {
if as, isASCII := makeASCIISet(chars); isASCII {
for i := 0; i < len(s); i++ {
@@ -154,10 +162,8 @@ func IndexAny(s, chars string) int {
}
}
for i, c := range s {
- for _, m := range chars {
- if c == m {
- return i
- }
+ if IndexRune(chars, c) >= 0 {
+ return i
}
}
return -1
@@ -171,6 +177,16 @@ func LastIndexAny(s, chars string) int {
// Avoid scanning all of s.
return -1
}
+ if len(s) == 1 {
+ rc := rune(s[0])
+ if rc >= utf8.RuneSelf {
+ rc = utf8.RuneError
+ }
+ if IndexRune(chars, rc) >= 0 {
+ return 0
+ }
+ return -1
+ }
if len(s) > 8 {
if as, isASCII := makeASCIISet(chars); isASCII {
for i := len(s) - 1; i >= 0; i-- {
@@ -181,13 +197,25 @@ func LastIndexAny(s, chars string) int {
return -1
}
}
+ if len(chars) == 1 {
+ rc := rune(chars[0])
+ if rc >= utf8.RuneSelf {
+ rc = utf8.RuneError
+ }
+ for i := len(s); i > 0; {
+ r, size := utf8.DecodeLastRuneInString(s[:i])
+ i -= size
+ if rc == r {
+ return i
+ }
+ }
+ return -1
+ }
for i := len(s); i > 0; {
r, size := utf8.DecodeLastRuneInString(s[:i])
i -= size
- for _, c := range chars {
- if r == c {
- return i
- }
+ if IndexRune(chars, r) >= 0 {
+ return i
}
}
return -1
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index 984fecfa8d..c01c4dabc5 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -153,6 +153,7 @@ var indexAnyTests = []IndexTest{
{"", "abc", -1},
{"a", "", -1},
{"a", "a", 0},
+ {"\x80", "\xffb", 0},
{"aaa", "a", 0},
{"abc", "xyz", -1},
{"abc", "xcz", 2},
@@ -163,6 +164,7 @@ var indexAnyTests = []IndexTest{
{dots + dots + dots, " ", -1},
{"012abcba210", "\xffb", 4},
{"012\x80bcb\x80210", "\xffb", 3},
+ {"0123456\xcf\x80abc", "\xcfb\x80", 10},
}
var lastIndexAnyTests = []IndexTest{
@@ -171,6 +173,7 @@ var lastIndexAnyTests = []IndexTest{
{"", "abc", -1},
{"a", "", -1},
{"a", "a", 0},
+ {"\x80", "\xffb", 0},
{"aaa", "a", 2},
{"abc", "xyz", -1},
{"abc", "ab", 1},
@@ -181,6 +184,7 @@ var lastIndexAnyTests = []IndexTest{
{dots + dots + dots, " ", -1},
{"012abcba210", "\xffb", 6},
{"012\x80bcb\x80210", "\xffb", 7},
+ {"0123456\xcf\x80abc", "\xcfb\x80", 10},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -1787,10 +1791,24 @@ func BenchmarkRepeat(b *testing.B) {
}
func BenchmarkIndexAnyASCII(b *testing.B) {
- x := Repeat("#", 4096) // Never matches set
- cs := "0123456789abcdef"
- for k := 1; k <= 4096; k <<= 4 {
- for j := 1; j <= 16; j <<= 1 {
+ x := Repeat("#", 2048) // Never matches set
+ cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
+ for k := 1; k <= 2048; k <<= 4 {
+ for j := 1; j <= 64; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ IndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
+func BenchmarkIndexAnyUTF8(b *testing.B) {
+ x := Repeat("#", 2048) // Never matches set
+ cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
+ for k := 1; k <= 2048; k <<= 4 {
+ for j := 1; j <= 64; j <<= 1 {
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
for i := 0; i < b.N; i++ {
IndexAny(x[:k], cs[:j])
@@ -1800,6 +1818,34 @@ func BenchmarkIndexAnyASCII(b *testing.B) {
}
}
+func BenchmarkLastIndexAnyASCII(b *testing.B) {
+ x := Repeat("#", 2048) // Never matches set
+ cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
+ for k := 1; k <= 2048; k <<= 4 {
+ for j := 1; j <= 64; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ LastIndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
+func BenchmarkLastIndexAnyUTF8(b *testing.B) {
+ x := Repeat("#", 2048) // Never matches set
+ cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
+ for k := 1; k <= 2048; k <<= 4 {
+ for j := 1; j <= 64; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ LastIndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
func BenchmarkTrimASCII(b *testing.B) {
cs := "0123456789abcdef"
for k := 1; k <= 4096; k <<= 4 {