aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/strings/strings.go
diff options
context:
space:
mode:
authorDonovan Hide <donovanhide@gmail.com>2013-02-19 10:36:15 -0500
committerRuss Cox <rsc@golang.org>2013-02-19 10:36:15 -0500
commit937f91e1daadfe55aa57e3482485494a0765c849 (patch)
treef8251cffce4656dc2eafd5d4c4e161e18f0f79a4 /src/pkg/strings/strings.go
parent9704c80b93c569d8bdb3eaa90d47a52168c51ee0 (diff)
downloadgo-937f91e1daadfe55aa57e3482485494a0765c849.tar.xz
strings: faster Count, Index
Slightly better benchmarks for when string and separator are equivalent and also less branching in inner loops. benchmark old ns/op new ns/op delta BenchmarkGenericNoMatch 3430 3442 +0.35% BenchmarkGenericMatch1 23590 22855 -3.12% BenchmarkGenericMatch2 108031 105025 -2.78% BenchmarkSingleMaxSkipping 2969 2704 -8.93% BenchmarkSingleLongSuffixFail 2826 2572 -8.99% BenchmarkSingleMatch 205268 197832 -3.62% BenchmarkByteByteNoMatch 987 921 -6.69% BenchmarkByteByteMatch 2014 1749 -13.16% BenchmarkByteStringMatch 3083 3050 -1.07% BenchmarkHTMLEscapeNew 922 915 -0.76% BenchmarkHTMLEscapeOld 1654 1570 -5.08% BenchmarkByteByteReplaces 11897 11556 -2.87% BenchmarkByteByteMap 4485 4255 -5.13% BenchmarkIndexRune 174 121 -30.46% BenchmarkIndexRuneFastPath 41 41 -0.24% BenchmarkIndex 45 44 -0.22% BenchmarkMapNoChanges 433 431 -0.46% BenchmarkIndexHard1 4015336 3316490 -17.40% BenchmarkIndexHard2 3976254 3395627 -14.60% BenchmarkIndexHard3 3973158 3378329 -14.97% BenchmarkCountHard1 4403549 3448512 -21.69% BenchmarkCountHard2 4387437 3413059 -22.21% BenchmarkCountHard3 4403891 3382661 -23.19% BenchmarkIndexTorture 28354 25864 -8.78% BenchmarkCountTorture 29625 27463 -7.30% BenchmarkFields 38752040 39169840 +1.08% BenchmarkFieldsFunc 38797765 38888060 +0.23% benchmark old MB/s new MB/s speedup BenchmarkSingleMaxSkipping 3367.07 3697.62 1.10x BenchmarkSingleLongSuffixFail 354.51 389.47 1.10x BenchmarkSingleMatch 73.07 75.82 1.04x BenchmarkFields 27.06 26.77 0.99x BenchmarkFieldsFunc 27.03 26.96 1.00x R=dave, fullung, remyoudompheng, rsc CC=golang-dev https://golang.org/cl/7350045
Diffstat (limited to 'src/pkg/strings/strings.go')
-rw-r--r--src/pkg/strings/strings.go67
1 files changed, 39 insertions, 28 deletions
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index 72b8d223af..9203fc5140 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -59,21 +59,26 @@ func hashstr(sep string) (uint32, uint32) {
// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep string) int {
- if sep == "" {
- return utf8.RuneCountInString(s) + 1
- }
- c := sep[0]
n := 0
- if len(sep) == 1 {
+ // special cases
+ switch {
+ case len(sep) == 0:
+ return utf8.RuneCountInString(s) + 1
+ case len(sep) == 1:
// special case worth making fast
+ c := sep[0]
for i := 0; i < len(s); i++ {
if s[i] == c {
n++
}
}
return n
- }
- if len(sep) > len(s) {
+ case len(sep) > len(s):
+ return 0
+ case len(sep) == len(s):
+ if sep == s {
+ return 1
+ }
return 0
}
hashsep, pow := hashstr(sep)
@@ -82,17 +87,19 @@ func Count(s, sep string) int {
h = h*primeRK + uint32(s[i])
}
lastmatch := 0
- for i := len(sep); ; i++ {
- // Invariant: h = hash(s[i-l : i])
+ if h == hashsep && s[:len(sep)] == sep {
+ n++
+ lastmatch = len(sep)
+ }
+ for i := len(sep); i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-len(sep)])
+ i++
if h == hashsep && lastmatch <= i-len(sep) && s[i-len(sep):i] == sep {
n++
lastmatch = i
}
- if i >= len(s) {
- break
- }
- h = h*primeRK + uint32(s[i])
- h -= pow * uint32(s[i-len(sep)])
}
return n
}
@@ -115,11 +122,11 @@ func ContainsRune(s string, r rune) bool {
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
n := len(sep)
- if n == 0 {
+ switch {
+ case n == 0:
return 0
- }
- c := sep[0]
- if n == 1 {
+ case n == 1:
+ c := sep[0]
// special case worth making fast
for i := 0; i < len(s); i++ {
if s[i] == c {
@@ -127,9 +134,12 @@ func Index(s, sep string) int {
}
}
return -1
- }
- // n > 1
- if n > len(s) {
+ case n == len(s):
+ if sep == s {
+ return 0
+ }
+ return -1
+ case n > len(s):
return -1
}
// Hash sep.
@@ -138,16 +148,17 @@ func Index(s, sep string) int {
for i := 0; i < n; i++ {
h = h*primeRK + uint32(s[i])
}
- for i := n; ; i++ {
- // Invariant: h = hash(s[i-n : i])
+ if h == hashsep && s[:n] == sep {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
if h == hashsep && s[i-n:i] == sep {
return i - n
}
- if i >= len(s) {
- break
- }
- h = h*primeRK + uint32(s[i])
- h -= pow * uint32(s[i-n])
}
return -1
}