]> Cypherpunks repositories - gostls13.git/commitdiff
strings: add fast path to Replace
authorRui Ueyama <ruiu@google.com>
Wed, 18 Jun 2014 05:08:46 +0000 (22:08 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 18 Jun 2014 05:08:46 +0000 (22:08 -0700)
genericReplacer.lookup is called for each byte of an input
string. In many (most?) cases, lookup will fail for the first
byte, and it will return immediately. Adding a fast path for
that case seems worth it.

Benchmark on my Xeon 3.5GHz Linux box:

benchmark                        old ns/op    new ns/op    delta
BenchmarkGenericNoMatch               2691          774  -71.24%
BenchmarkGenericMatch1                7920         8151   +2.92%
BenchmarkGenericMatch2               52336        39927  -23.71%
BenchmarkSingleMaxSkipping            1575         1575   +0.00%
BenchmarkSingleLongSuffixFail         1429         1429   +0.00%
BenchmarkSingleMatch                 56228        55444   -1.39%
BenchmarkByteByteNoMatch               568          568   +0.00%
BenchmarkByteByteMatch                 977          972   -0.51%
BenchmarkByteStringMatch              1669         1687   +1.08%
BenchmarkHTMLEscapeNew                 422          422   +0.00%
BenchmarkHTMLEscapeOld                 692          670   -3.18%
BenchmarkByteByteReplaces             8492         8474   -0.21%
BenchmarkByteByteMap                  2817         2808   -0.32%

LGTM=rsc
R=golang-codereviews, bradfitz, dave, rsc
CC=golang-codereviews
https://golang.org/cl/79200044

src/pkg/strings/replace.go

index 3e05d2057bef48181cc80dcdbc76e0f6b7862ad0..16889bac99286c4a14f67a3f0d50a3b5f165bf2e 100644 (file)
@@ -323,6 +323,15 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error)
        var last, wn int
        var prevMatchEmpty bool
        for i := 0; i <= len(s); {
+               // Fast path: s[i] is not a prefix of any pattern.
+               if i != len(s) && r.root.priority == 0 {
+                       index := int(r.mapping[s[i]])
+                       if index == r.tableSize || r.root.table[index] == nil {
+                               i++
+                               continue
+                       }
+               }
+
                // Ignore the empty match iff the previous loop found the empty match.
                val, keylen, match := r.lookup(s[i:], prevMatchEmpty)
                prevMatchEmpty = match && keylen == 0