Skip to content

Commit c5430dc

Browse files
bborehamgopherbot
authored andcommitted
regexp: allow patterns with no alternates to be one-pass
Check whether a regex has any 'alt' instructions before rejecting it as one-pass. Previously `^abc` would run the backtrack matcher. I tried to make the comment match what the code does now. Updates #21463 ``` name old time/op new time/op delta Find-8 167ns ± 1% 170ns ± 3% ~ (p=0.500 n=5+5) FindAllNoMatches-8 88.8ns ± 5% 87.3ns ± 0% ~ (p=0.095 n=5+5) FindString-8 166ns ± 3% 164ns ± 0% ~ (p=0.063 n=5+5) FindSubmatch-8 191ns ± 1% 191ns ± 0% ~ (p=0.556 n=4+5) FindStringSubmatch-8 183ns ± 0% 182ns ± 0% -0.43% (p=0.048 n=5+5) Literal-8 50.3ns ± 0% 50.1ns ± 0% -0.40% (p=0.016 n=5+4) NotLiteral-8 914ns ± 0% 927ns ± 7% ~ (p=0.730 n=5+5) MatchClass-8 1.20µs ± 1% 1.22µs ± 6% ~ (p=0.738 n=5+5) MatchClass_InRange-8 1.20µs ± 6% 1.21µs ± 6% ~ (p=0.548 n=5+5) ReplaceAll-8 796ns ± 0% 792ns ± 0% -0.51% (p=0.032 n=5+5) AnchoredLiteralShortNonMatch-8 41.0ns ± 2% 34.2ns ± 2% -16.47% (p=0.008 n=5+5) AnchoredLiteralLongNonMatch-8 53.3ns ± 0% 34.3ns ± 3% -35.74% (p=0.008 n=5+5) AnchoredShortMatch-8 74.0ns ± 2% 75.8ns ± 0% +2.46% (p=0.032 n=5+4) AnchoredLongMatch-8 146ns ± 3% 76ns ± 1% -48.12% (p=0.008 n=5+5) OnePassShortA-8 424ns ± 0% 423ns ± 0% ~ (p=0.222 n=5+4) NotOnePassShortA-8 373ns ± 1% 375ns ± 2% ~ (p=0.690 n=5+5) OnePassShortB-8 315ns ± 2% 308ns ± 0% -2.12% (p=0.008 n=5+5) NotOnePassShortB-8 244ns ± 3% 239ns ± 0% ~ (p=0.476 n=5+5) OnePassLongPrefix-8 61.6ns ± 2% 60.9ns ± 0% -1.13% (p=0.016 n=5+4) OnePassLongNotPrefix-8 236ns ± 3% 230ns ± 0% ~ (p=0.143 n=5+5) ``` Change-Id: I8a94b53bc761cd7ec89923c905ec8baaaa58a5fd GitHub-Last-Rev: e9e0c29 GitHub-Pull-Request: #48748 Reviewed-on: https://go-review.googlesource.com/c/go/+/353711 Reviewed-by: Daniel Martí <[email protected]> Reviewed-by: Russ Cox <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 8659ad9 commit c5430dc

File tree

2 files changed

+12
-2
lines changed

2 files changed

+12
-2
lines changed

src/regexp/onepass.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,20 @@ func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
465465
syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
466466
return nil
467467
}
468-
// every instruction leading to InstMatch must be EmptyEndText
468+
hasAlt := false
469+
for _, inst := range prog.Inst {
470+
if inst.Op == syntax.InstAlt || inst.Op == syntax.InstAltMatch {
471+
hasAlt = true
472+
break
473+
}
474+
}
475+
// If we have alternates, every instruction leading to InstMatch must be EmptyEndText.
476+
// Also, any match on empty text must be $.
469477
for _, inst := range prog.Inst {
470478
opOut := prog.Inst[inst.Out].Op
471479
switch inst.Op {
472480
default:
473-
if opOut == syntax.InstMatch {
481+
if opOut == syntax.InstMatch && hasAlt {
474482
return nil
475483
}
476484
case syntax.InstAlt, syntax.InstAltMatch:

src/regexp/onepass_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ var onePassTests = []struct {
142142
{`^(?:(a)|(?:a*))$`, false},
143143
{`^(?:(?:(?:.(?:$))?))$`, true},
144144
{`^abcd$`, true},
145+
{`^abcd`, true},
145146
{`^(?:(?:a{0,})*?)$`, false},
146147
{`^(?:(?:a+)*)$`, true},
147148
{`^(?:(?:a|(?:aa)))$`, true},
@@ -154,6 +155,7 @@ var onePassTests = []struct {
154155
{`^(?:(?:aa)|a)$`, true},
155156
{`^[a-c]*`, false},
156157
{`^...$`, true},
158+
{`^...`, true},
157159
{`^(?:a|(?:aa))$`, true},
158160
{`^a((b))c$`, true},
159161
{`^a.[l-nA-Cg-j]?e$`, true},

0 commit comments

Comments
 (0)