]> Cypherpunks repositories - gostls13.git/commitdiff
go/doc: compile regexps lazily
authorBrad Fitzpatrick <bradfitz@golang.org>
Fri, 3 Aug 2018 19:21:11 +0000 (19:21 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 21 Aug 2018 02:51:10 +0000 (02:51 +0000)
Compile go/doc's 4 regexps lazily, on demand.

Also, add a test for the one that had no test coverage.

This reduces init-time CPU as well as heap by ~20KB when they're not
used, which seems to be common enough. As an example, cmd/doc only
seems to use 1 of them. (as noted by temporary print statements)

Updates #26775

Change-Id: I85df89b836327a53fb8e1ace3f92480374270368
Reviewed-on: https://go-review.googlesource.com/127875
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/go/build/deps_test.go
src/go/doc/comment.go
src/go/doc/doc_test.go
src/go/doc/lazyre.go [new file with mode: 0644]
src/go/doc/reader.go

index 29dbe47d29d4720821f5eca47b185e831232f82e..7a154b08803e9fecce435bb7c105b11a58afc9fb 100644 (file)
@@ -204,7 +204,7 @@ var pkgDeps = map[string][]string{
 
        // Go parser.
        "go/ast":     {"L4", "OS", "go/scanner", "go/token"},
-       "go/doc":     {"L4", "go/ast", "go/token", "regexp", "text/template"},
+       "go/doc":     {"L4", "OS", "go/ast", "go/token", "regexp", "text/template"},
        "go/parser":  {"L4", "OS", "go/ast", "go/scanner", "go/token"},
        "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
        "go/scanner": {"L4", "OS", "go/token"},
index d068d8960c602d5a7fde6a324b456068284aebb4..d9268b87fb885b3c00e027b314a2306732c792e7 100644 (file)
@@ -8,7 +8,6 @@ package doc
 
 import (
        "io"
-       "regexp"
        "strings"
        "text/template" // for HTMLEscape
        "unicode"
@@ -63,7 +62,7 @@ const (
        urlRx = protoPart + `://` + hostPart + pathPart
 )
 
-var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
+var matchRx = newLazyRE(`(` + urlRx + `)|(` + identRx + `)`)
 
 var (
        html_a      = []byte(`<a href="`)
@@ -276,7 +275,7 @@ type block struct {
        lines []string
 }
 
-var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`)
+var nonAlphaNumRx = newLazyRE(`[^a-zA-Z0-9]`)
 
 func anchorID(line string) string {
        // Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols.
index ad8ba5378f3f13f7db193b5416bebb4439d0c18c..902a79f63f59a40fcb8e9bfe4c44255e9faf110c 100644 (file)
@@ -144,3 +144,12 @@ func Test(t *testing.T) {
        test(t, AllDecls)
        test(t, AllMethods)
 }
+
+func TestAnchorID(t *testing.T) {
+       const in = "Important Things 2 Know & Stuff"
+       const want = "hdr-Important_Things_2_Know___Stuff"
+       got := anchorID(in)
+       if got != want {
+               t.Errorf("anchorID(%q) = %q; want %q", in, got, want)
+       }
+}
diff --git a/src/go/doc/lazyre.go b/src/go/doc/lazyre.go
new file mode 100644 (file)
index 0000000..3fd97d4
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2018 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 doc
+
+import (
+       "os"
+       "regexp"
+       "strings"
+       "sync"
+)
+
+type lazyRE struct {
+       str  string
+       once sync.Once
+       rx   *regexp.Regexp
+}
+
+func (r *lazyRE) re() *regexp.Regexp {
+       r.once.Do(r.build)
+       return r.rx
+}
+
+func (r *lazyRE) build() {
+       r.rx = regexp.MustCompile(r.str)
+       r.str = ""
+}
+
+func (r *lazyRE) FindStringSubmatchIndex(s string) []int {
+       return r.re().FindStringSubmatchIndex(s)
+}
+
+func (r *lazyRE) ReplaceAllString(src, repl string) string {
+       return r.re().ReplaceAllString(src, repl)
+}
+
+func (r *lazyRE) MatchString(s string) bool {
+       return r.re().MatchString(s)
+}
+
+var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
+
+func newLazyRE(str string) *lazyRE {
+       lr := &lazyRE{str: str}
+       if inTest {
+               // In tests, always compile the regexps early.
+               lr.re()
+       }
+       return lr
+}
index 21c02920ababf56ee8d789166a4c5f1241e7397e..21d5907a0302791e2880a5c51d1f56b284edf864 100644 (file)
@@ -7,7 +7,6 @@ package doc
 import (
        "go/ast"
        "go/token"
-       "regexp"
        "sort"
        "strconv"
 )
@@ -425,9 +424,9 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
 }
 
 var (
-       noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`                    // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
-       noteMarkerRx  = regexp.MustCompile(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start
-       noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
+       noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`           // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
+       noteMarkerRx  = newLazyRE(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start
+       noteCommentRx = newLazyRE(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
 )
 
 // readNote collects a single note from a sequence of comments.