1
0
mirror of https://github.com/golang/go synced 2024-09-30 11:28:36 -06:00

strings: make IndexRune faster

re-implement IndexRune by Index which is well optimized to get
performance gain.

name                   old time/op  new time/op  delta
IndexRune-4            30.2ns ± 1%  28.3ns ± 1%   -6.22%  (p=0.000 n=20+19)
IndexRuneLongString-4   156ns ± 1%    49ns ± 1%  -68.72%  (p=0.000 n=19+19)
IndexRuneFastPath-4    10.6ns ± 2%  10.0ns ± 1%   -6.30%  (p=0.000 n=18+18)

Change-Id: Ie663b8f7860ca51892dd4be182fca3caa5f8ae61
Reviewed-on: https://go-review.googlesource.com/28546
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Hiroshi Ioka 2016-09-06 20:23:40 +09:00 committed by Brad Fitzpatrick
parent a4bdd64555
commit 8737dac1f2
3 changed files with 30 additions and 9 deletions

View File

@ -176,17 +176,11 @@ func LastIndex(s, sep string) int {
// IndexRune returns the index of the first instance of the Unicode code point
// r, or -1 if rune is not present in s.
func IndexRune(s string, r rune) int {
switch {
case r < utf8.RuneSelf:
if r < utf8.RuneSelf {
return IndexByte(s, byte(r))
default:
for i, c := range s {
if c == r {
return i
}
}
}
return -1
return Index(s, string(r))
}
// IndexAny returns the index of the first instance of any Unicode code point

View File

@ -4,6 +4,8 @@
package strings
//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_$GOARCH.s

View File

@ -244,6 +244,20 @@ func TestIndexRune(t *testing.T) {
t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out)
}
}
haystack := "test世界"
allocs := testing.AllocsPerRun(1000, func() {
if i := IndexRune(haystack, 's'); i != 2 {
t.Fatalf("'s' at %d; want 2", i)
}
if i := IndexRune(haystack, '世'); i != 4 {
t.Fatalf("'世' at %d; want 4", i)
}
})
if allocs != 0 {
t.Errorf(`expected no allocations, got %f`, allocs)
}
}
const benchmarkString = "some_text=some☺value"
@ -257,6 +271,17 @@ func BenchmarkIndexRune(b *testing.B) {
}
}
var benchmarkLongString = Repeat(" ", 100) + benchmarkString
func BenchmarkIndexRuneLongString(b *testing.B) {
if got := IndexRune(benchmarkLongString, '☺'); got != 114 {
b.Fatalf("wrong index: expected 114, got=%d", got)
}
for i := 0; i < b.N; i++ {
IndexRune(benchmarkLongString, '☺')
}
}
func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 {
b.Fatalf("wrong index: expected 17, got=%d", got)