Commit 9aed16e9 authored by Ingo Oeser's avatar Ingo Oeser Committed by Brad Fitzpatrick

regexp: avoid alloc in QuoteMeta when not quoting

Many users quote literals in regular expressions just in case.
No need to allocate then.

Note: Also added benchmarks for quoting and not quoting.

	name             old time/op    new time/op     delta
	QuoteMetaAll-4      629ns ± 6%      654ns ± 5%    +4.01%        (p=0.001 n=20+19)
	QuoteMetaNone-4    1.02µs ± 6%     0.20µs ± 0%   -80.73%        (p=0.000 n=18+20)

	name             old speed      new speed       delta
	QuoteMetaAll-4   22.3MB/s ± 6%   21.4MB/s ± 5%    -3.94%        (p=0.001 n=20+19)
	QuoteMetaNone-4  25.3MB/s ± 3%  131.5MB/s ± 0%  +419.28%        (p=0.000 n=17+19)

	name             old alloc/op   new alloc/op    delta
	QuoteMetaAll-4      64.0B ± 0%      64.0B ± 0%      ~     (all samples are equal)
	QuoteMetaNone-4     96.0B ± 0%      0.0B ±NaN%  -100.00%        (p=0.000 n=20+20)

	name             old allocs/op  new allocs/op   delta
	QuoteMetaAll-4       2.00 ± 0%       2.00 ± 0%      ~     (all samples are equal)
	QuoteMetaNone-4      2.00 ± 0%      0.00 ±NaN%  -100.00%        (p=0.000 n=20+20)

Change-Id: I38d50f463cde463115d22534f8eb849e54d899af
Reviewed-on: https://go-review.googlesource.com/31395Reviewed-by: default avatarRuss Cox <rsc@golang.org>
Reviewed-by: default avatarAustin Clements <austin@google.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent f36e1ada
...@@ -818,3 +818,23 @@ func BenchmarkMatchParallelCopied(b *testing.B) { ...@@ -818,3 +818,23 @@ func BenchmarkMatchParallelCopied(b *testing.B) {
} }
}) })
} }
var sink string
func BenchmarkQuoteMetaAll(b *testing.B) {
s := string(specialBytes)
b.SetBytes(int64(len(s)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
sink = QuoteMeta(s)
}
}
func BenchmarkQuoteMetaNone(b *testing.B) {
s := "abcdefghijklmnopqrstuvwxyz"
b.SetBytes(int64(len(s)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
sink = QuoteMeta(s)
}
}
...@@ -600,11 +600,22 @@ func special(b byte) bool { ...@@ -600,11 +600,22 @@ func special(b byte) bool {
// inside the argument text; the returned string is a regular expression matching // inside the argument text; the returned string is a regular expression matching
// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`. // the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
func QuoteMeta(s string) string { func QuoteMeta(s string) string {
b := make([]byte, 2*len(s))
// A byte loop is correct because all metacharacters are ASCII. // A byte loop is correct because all metacharacters are ASCII.
j := 0 var i int
for i := 0; i < len(s); i++ { for i = 0; i < len(s); i++ {
if special(s[i]) {
break
}
}
// No meta characters found, so return original string.
if i >= len(s) {
return s
}
b := make([]byte, 2*len(s)-i)
copy(b, s[:i])
j := i
for ; i < len(s); i++ {
if special(s[i]) { if special(s[i]) {
b[j] = '\\' b[j] = '\\'
j++ j++
...@@ -612,7 +623,7 @@ func QuoteMeta(s string) string { ...@@ -612,7 +623,7 @@ func QuoteMeta(s string) string {
b[j] = s[i] b[j] = s[i]
j++ j++
} }
return string(b[0:j]) return string(b[:j])
} }
// The number of capture values in the program may correspond // The number of capture values in the program may correspond
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment