mirror of
https://github.com/golang/go
synced 2024-11-20 04:24:51 -07:00
f5c1926e93
It reduces needless allocations on compiling onepass regex. name old time/op new time/op delta CompileOnepass/^(?:(?:(?:.(?:$))?))...-4 6.31µs ± 3% 6.11µs ± 3% ~ (p=0.056 n=5+5) CompileOnepass/^abcd$-4 5.69µs ±12% 4.93µs ± 4% -13.42% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a{0,})*?)$-4 7.10µs ±12% 5.82µs ± 5% -17.95% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a+)*)$-4 5.99µs ±10% 6.07µs ±11% ~ (p=1.000 n=5+5) CompileOnepass/^(?:(?:a|(?:aa)))$-4 7.36µs ± 4% 7.81µs ±19% ~ (p=0.310 n=5+5) CompileOnepass/^(?:[^\s\S])$-4 4.71µs ± 3% 4.71µs ± 5% ~ (p=1.000 n=5+5) CompileOnepass/^(?:(?:(?:a*)+))$-4 6.06µs ± 2% 6.23µs ± 9% ~ (p=0.310 n=5+5) CompileOnepass/^[a-c]+$-4 4.74µs ± 4% 4.64µs ± 6% ~ (p=0.421 n=5+5) CompileOnepass/^[a-c]*$-4 5.17µs ± 2% 4.68µs ± 0% -9.57% (p=0.016 n=5+4) CompileOnepass/^(?:a*)$-4 5.34µs ± 3% 5.08µs ±12% ~ (p=0.151 n=5+5) CompileOnepass/^(?:(?:aa)|a)$-4 7.24µs ± 5% 7.33µs ±12% ~ (p=0.841 n=5+5) CompileOnepass/^...$-4 5.28µs ± 3% 4.99µs ± 9% ~ (p=0.095 n=5+5) CompileOnepass/^(?:a|(?:aa))$-4 7.20µs ± 4% 7.24µs ±10% ~ (p=0.841 n=5+5) CompileOnepass/^a((b))c$-4 7.99µs ± 3% 7.76µs ± 8% ~ (p=0.151 n=5+5) CompileOnepass/^a.[l-nA-Cg-j]?e$-4 8.30µs ± 5% 7.29µs ± 4% -12.08% (p=0.008 n=5+5) CompileOnepass/^a((b))$-4 7.34µs ± 4% 7.24µs ±19% ~ (p=0.690 n=5+5) CompileOnepass/^a(?:(b)|(c))c$-4 9.80µs ± 6% 9.49µs ±18% ~ (p=0.151 n=5+5) CompileOnepass/^a(?:b|c)$-4 5.23µs ± 3% 4.80µs ±10% ~ (p=0.056 n=5+5) CompileOnepass/^a(?:b?|c)$-4 8.26µs ± 3% 7.30µs ± 3% -11.62% (p=0.008 n=5+5) CompileOnepass/^a(?:b?|c+)$-4 9.18µs ± 2% 8.16µs ± 2% -11.06% (p=0.008 n=5+5) CompileOnepass/^a(?:bc)+$-4 6.16µs ± 3% 6.41µs ±13% ~ (p=0.548 n=5+5) CompileOnepass/^a(?:[bcd])+$-4 5.75µs ± 5% 5.50µs ±12% ~ (p=0.151 n=5+5) CompileOnepass/^a((?:[bcd])+)$-4 7.65µs ± 5% 6.93µs ± 9% ~ (p=0.056 n=5+5) CompileOnepass/^a(:?b|c)*d$-4 13.0µs ± 1% 12.1µs ± 2% -6.91% (p=0.008 n=5+5) CompileOnepass/^.bc(d|e)*$-4 9.20µs ± 4% 8.25µs ± 3% -10.38% (p=0.008 n=5+5) CompileOnepass/^loooooooooooooooooo...-4 254µs ± 2% 220µs ± 6% -13.47% (p=0.008 n=5+5) name old alloc/op new alloc/op delta CompileOnepass/^(?:(?:(?:.(?:$))?))...-4 3.92kB ± 0% 3.41kB ± 0% -13.06% (p=0.008 n=5+5) CompileOnepass/^abcd$-4 3.20kB ± 0% 2.75kB ± 0% -14.00% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a{0,})*?)$-4 3.85kB ± 0% 3.34kB ± 0% -13.31% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a+)*)$-4 3.46kB ± 0% 2.95kB ± 0% -14.78% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a|(?:aa)))$-4 4.20kB ± 0% 3.75kB ± 0% -10.67% (p=0.008 n=5+5) CompileOnepass/^(?:[^\s\S])$-4 3.10kB ± 0% 2.46kB ± 0% -20.62% (p=0.008 n=5+5) CompileOnepass/^(?:(?:(?:a*)+))$-4 3.64kB ± 0% 3.13kB ± 0% -14.07% (p=0.008 n=5+5) CompileOnepass/^[a-c]+$-4 3.06kB ± 0% 2.48kB ± 0% -18.85% (p=0.008 n=5+5) CompileOnepass/^[a-c]*$-4 3.10kB ± 0% 2.52kB ± 0% -18.60% (p=0.008 n=5+5) CompileOnepass/^(?:a*)$-4 3.21kB ± 0% 2.63kB ± 0% -17.96% (p=0.008 n=5+5) CompileOnepass/^(?:(?:aa)|a)$-4 4.09kB ± 0% 3.64kB ± 0% -10.96% (p=0.008 n=5+5) CompileOnepass/^...$-4 3.42kB ± 0% 2.91kB ± 0% -14.95% (p=0.008 n=5+5) CompileOnepass/^(?:a|(?:aa))$-4 4.09kB ± 0% 3.64kB ± 0% -10.96% (p=0.008 n=5+5) CompileOnepass/^a((b))c$-4 5.67kB ± 0% 4.39kB ± 0% -22.59% (p=0.008 n=5+5) CompileOnepass/^a.[l-nA-Cg-j]?e$-4 5.73kB ± 0% 4.32kB ± 0% -24.58% (p=0.008 n=5+5) CompileOnepass/^a((b))$-4 5.41kB ± 0% 4.06kB ± 0% -24.85% (p=0.008 n=5+5) CompileOnepass/^a(?:(b)|(c))c$-4 6.40kB ± 0% 5.31kB ± 0% -17.00% (p=0.008 n=5+5) CompileOnepass/^a(?:b|c)$-4 3.46kB ± 0% 2.88kB ± 0% -16.67% (p=0.008 n=5+5) CompileOnepass/^a(?:b?|c)$-4 5.77kB ± 0% 4.36kB ± 0% -24.41% (p=0.008 n=5+5) CompileOnepass/^a(?:b?|c+)$-4 5.94kB ± 0% 4.59kB ± 0% -22.64% (p=0.008 n=5+5) CompileOnepass/^a(?:bc)+$-4 3.60kB ± 0% 3.15kB ± 0% -12.44% (p=0.008 n=5+5) CompileOnepass/^a(?:[bcd])+$-4 3.46kB ± 0% 2.94kB ± 0% -14.81% (p=0.008 n=5+5) CompileOnepass/^a((?:[bcd])+)$-4 5.50kB ± 0% 4.09kB ± 0% -25.62% (p=0.008 n=5+5) CompileOnepass/^a(:?b|c)*d$-4 7.24kB ± 0% 6.15kB ± 0% -15.03% (p=0.008 n=5+5) CompileOnepass/^.bc(d|e)*$-4 5.75kB ± 0% 4.47kB ± 0% -22.25% (p=0.008 n=5+5) CompileOnepass/^loooooooooooooooooo...-4 225kB ± 0% 135kB ± 0% -39.99% (p=0.008 n=5+5) name old allocs/op new allocs/op delta CompileOnepass/^(?:(?:(?:.(?:$))?))...-4 52.0 ± 0% 49.0 ± 0% -5.77% (p=0.008 n=5+5) CompileOnepass/^abcd$-4 44.0 ± 0% 41.0 ± 0% -6.82% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a{0,})*?)$-4 52.0 ± 0% 49.0 ± 0% -5.77% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a+)*)$-4 47.0 ± 0% 44.0 ± 0% -6.38% (p=0.008 n=5+5) CompileOnepass/^(?:(?:a|(?:aa)))$-4 57.0 ± 0% 54.0 ± 0% -5.26% (p=0.008 n=5+5) CompileOnepass/^(?:[^\s\S])$-4 36.0 ± 0% 33.0 ± 0% -8.33% (p=0.008 n=5+5) CompileOnepass/^(?:(?:(?:a*)+))$-4 49.0 ± 0% 46.0 ± 0% -6.12% (p=0.008 n=5+5) CompileOnepass/^[a-c]+$-4 39.0 ± 0% 36.0 ± 0% -7.69% (p=0.008 n=5+5) CompileOnepass/^[a-c]*$-4 44.0 ± 0% 41.0 ± 0% -6.82% (p=0.008 n=5+5) CompileOnepass/^(?:a*)$-4 45.0 ± 0% 42.0 ± 0% -6.67% (p=0.008 n=5+5) CompileOnepass/^(?:(?:aa)|a)$-4 56.0 ± 0% 53.0 ± 0% -5.36% (p=0.008 n=5+5) CompileOnepass/^...$-4 46.0 ± 0% 43.0 ± 0% -6.52% (p=0.008 n=5+5) CompileOnepass/^(?:a|(?:aa))$-4 56.0 ± 0% 53.0 ± 0% -5.36% (p=0.008 n=5+5) CompileOnepass/^a((b))c$-4 57.0 ± 0% 53.0 ± 0% -7.02% (p=0.008 n=5+5) CompileOnepass/^a.[l-nA-Cg-j]?e$-4 62.0 ± 0% 58.0 ± 0% -6.45% (p=0.008 n=5+5) CompileOnepass/^a((b))$-4 51.0 ± 0% 47.0 ± 0% -7.84% (p=0.008 n=5+5) CompileOnepass/^a(?:(b)|(c))c$-4 69.0 ± 0% 65.0 ± 0% -5.80% (p=0.008 n=5+5) CompileOnepass/^a(?:b|c)$-4 43.0 ± 0% 40.0 ± 0% -6.98% (p=0.008 n=5+5) CompileOnepass/^a(?:b?|c)$-4 61.0 ± 0% 57.0 ± 0% -6.56% (p=0.008 n=5+5) CompileOnepass/^a(?:b?|c+)$-4 67.0 ± 0% 63.0 ± 0% -5.97% (p=0.008 n=5+5) CompileOnepass/^a(?:bc)+$-4 49.0 ± 0% 46.0 ± 0% -6.12% (p=0.008 n=5+5) CompileOnepass/^a(?:[bcd])+$-4 46.0 ± 0% 43.0 ± 0% -6.52% (p=0.008 n=5+5) CompileOnepass/^a((?:[bcd])+)$-4 53.0 ± 0% 49.0 ± 0% -7.55% (p=0.008 n=5+5) CompileOnepass/^a(:?b|c)*d$-4 109 ± 0% 105 ± 0% -3.67% (p=0.008 n=5+5) CompileOnepass/^.bc(d|e)*$-4 66.0 ± 0% 62.0 ± 0% -6.06% (p=0.008 n=5+5) CompileOnepass/^loooooooooooooooooo...-4 1.10k ± 0% 1.09k ± 0% -0.91% (p=0.008 n=5+5) Fixes #19735 Change-Id: Ic68503aaa08e42fafcf7e11cf1f584d674f5ea7b Reviewed-on: https://go-review.googlesource.com/38750 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
248 lines
5.1 KiB
Go
248 lines
5.1 KiB
Go
// Copyright 2014 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package regexp
|
|
|
|
import (
|
|
"reflect"
|
|
"regexp/syntax"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
var runeMergeTests = []struct {
|
|
left, right, merged []rune
|
|
next []uint32
|
|
leftPC, rightPC uint32
|
|
}{
|
|
{
|
|
// empty rhs
|
|
[]rune{69, 69},
|
|
[]rune{},
|
|
[]rune{69, 69},
|
|
[]uint32{1},
|
|
1, 2,
|
|
},
|
|
{
|
|
// identical runes, identical targets
|
|
[]rune{69, 69},
|
|
[]rune{69, 69},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 1,
|
|
},
|
|
{
|
|
// identical runes, different targets
|
|
[]rune{69, 69},
|
|
[]rune{69, 69},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// append right-first
|
|
[]rune{69, 69},
|
|
[]rune{71, 71},
|
|
[]rune{69, 69, 71, 71},
|
|
[]uint32{1, 2},
|
|
1, 2,
|
|
},
|
|
{
|
|
// append, left-first
|
|
[]rune{71, 71},
|
|
[]rune{69, 69},
|
|
[]rune{69, 69, 71, 71},
|
|
[]uint32{2, 1},
|
|
1, 2,
|
|
},
|
|
{
|
|
// successful interleave
|
|
[]rune{60, 60, 71, 71, 101, 101},
|
|
[]rune{69, 69, 88, 88},
|
|
[]rune{60, 60, 69, 69, 71, 71, 88, 88, 101, 101},
|
|
[]uint32{1, 2, 1, 2, 1},
|
|
1, 2,
|
|
},
|
|
{
|
|
// left surrounds right
|
|
[]rune{69, 74},
|
|
[]rune{71, 71},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// right surrounds left
|
|
[]rune{69, 74},
|
|
[]rune{68, 75},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// overlap at interval begin
|
|
[]rune{69, 74},
|
|
[]rune{74, 75},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// overlap ar interval end
|
|
[]rune{69, 74},
|
|
[]rune{65, 69},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// overlap from above
|
|
[]rune{69, 74},
|
|
[]rune{71, 74},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// overlap from below
|
|
[]rune{69, 74},
|
|
[]rune{65, 71},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
{
|
|
// out of order []rune
|
|
[]rune{69, 74, 60, 65},
|
|
[]rune{66, 67},
|
|
[]rune{},
|
|
[]uint32{mergeFailed},
|
|
1, 2,
|
|
},
|
|
}
|
|
|
|
func TestMergeRuneSet(t *testing.T) {
|
|
for ix, test := range runeMergeTests {
|
|
merged, next := mergeRuneSets(&test.left, &test.right, test.leftPC, test.rightPC)
|
|
if !reflect.DeepEqual(merged, test.merged) {
|
|
t.Errorf("mergeRuneSet :%d (%v, %v) merged\n have\n%v\nwant\n%v", ix, test.left, test.right, merged, test.merged)
|
|
}
|
|
if !reflect.DeepEqual(next, test.next) {
|
|
t.Errorf("mergeRuneSet :%d(%v, %v) next\n have\n%v\nwant\n%v", ix, test.left, test.right, next, test.next)
|
|
}
|
|
}
|
|
}
|
|
|
|
var onePass = &onePassProg{}
|
|
|
|
var onePassTests = []struct {
|
|
re string
|
|
onePass *onePassProg
|
|
}{
|
|
{`^(?:a|(?:a*))$`, notOnePass},
|
|
{`^(?:(a)|(?:a*))$`, notOnePass},
|
|
{`^(?:(?:(?:.(?:$))?))$`, onePass},
|
|
{`^abcd$`, onePass},
|
|
{`^(?:(?:a{0,})*?)$`, onePass},
|
|
{`^(?:(?:a+)*)$`, onePass},
|
|
{`^(?:(?:a|(?:aa)))$`, onePass},
|
|
{`^(?:[^\s\S])$`, onePass},
|
|
{`^(?:(?:a{3,4}){0,})$`, notOnePass},
|
|
{`^(?:(?:(?:a*)+))$`, onePass},
|
|
{`^[a-c]+$`, onePass},
|
|
{`^[a-c]*$`, onePass},
|
|
{`^(?:a*)$`, onePass},
|
|
{`^(?:(?:aa)|a)$`, onePass},
|
|
{`^[a-c]*`, notOnePass},
|
|
{`^...$`, onePass},
|
|
{`^(?:a|(?:aa))$`, onePass},
|
|
{`^a((b))c$`, onePass},
|
|
{`^a.[l-nA-Cg-j]?e$`, onePass},
|
|
{`^a((b))$`, onePass},
|
|
{`^a(?:(b)|(c))c$`, onePass},
|
|
{`^a(?:(b*)|(c))c$`, notOnePass},
|
|
{`^a(?:b|c)$`, onePass},
|
|
{`^a(?:b?|c)$`, onePass},
|
|
{`^a(?:b?|c?)$`, notOnePass},
|
|
{`^a(?:b?|c+)$`, onePass},
|
|
{`^a(?:b+|(bc))d$`, notOnePass},
|
|
{`^a(?:bc)+$`, onePass},
|
|
{`^a(?:[bcd])+$`, onePass},
|
|
{`^a((?:[bcd])+)$`, onePass},
|
|
{`^a(:?b|c)*d$`, onePass},
|
|
{`^.bc(d|e)*$`, onePass},
|
|
{`^(?:(?:aa)|.)$`, notOnePass},
|
|
{`^(?:(?:a{1,2}){1,2})$`, notOnePass},
|
|
{`^l` + strings.Repeat("o", 2<<8) + `ng$`, onePass},
|
|
}
|
|
|
|
func TestCompileOnePass(t *testing.T) {
|
|
var (
|
|
p *syntax.Prog
|
|
re *syntax.Regexp
|
|
err error
|
|
)
|
|
for _, test := range onePassTests {
|
|
if re, err = syntax.Parse(test.re, syntax.Perl); err != nil {
|
|
t.Errorf("Parse(%q) got err:%s, want success", test.re, err)
|
|
continue
|
|
}
|
|
// needs to be done before compile...
|
|
re = re.Simplify()
|
|
if p, err = syntax.Compile(re); err != nil {
|
|
t.Errorf("Compile(%q) got err:%s, want success", test.re, err)
|
|
continue
|
|
}
|
|
onePass = compileOnePass(p)
|
|
if (onePass == notOnePass) != (test.onePass == notOnePass) {
|
|
t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(cespare): Unify with onePassTests and rationalize one-pass test cases.
|
|
var onePassTests1 = []struct {
|
|
re string
|
|
match string
|
|
}{
|
|
{`^a(/b+(#c+)*)*$`, "a/b#c"}, // golang.org/issue/11905
|
|
}
|
|
|
|
func TestRunOnePass(t *testing.T) {
|
|
for _, test := range onePassTests1 {
|
|
re, err := Compile(test.re)
|
|
if err != nil {
|
|
t.Errorf("Compile(%q): got err: %s", test.re, err)
|
|
continue
|
|
}
|
|
if re.onepass == notOnePass {
|
|
t.Errorf("Compile(%q): got notOnePass, want one-pass", test.re)
|
|
continue
|
|
}
|
|
if !re.MatchString(test.match) {
|
|
t.Errorf("onepass %q did not match %q", test.re, test.match)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkCompileOnepass(b *testing.B) {
|
|
for _, test := range onePassTests {
|
|
if test.onePass == notOnePass {
|
|
continue
|
|
}
|
|
name := test.re
|
|
if len(name) > 20 {
|
|
name = name[:20] + "..."
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Compile(test.re); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|